retell-utils 0.3.2 → 0.4.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.
package/dist/llm.js ADDED
@@ -0,0 +1,118 @@
1
+ import { z } from "zod";
2
+ import { KbConfigSchema, McpConfigSchema } from "./agent.js";
3
+ import { LlmModelSchema, LlmToolTypeSchema, S2sModelSchema, StartSpeakerSchema, ToolHttpMethodSchema, ToolParameterTypeSchema, } from "./enums.js";
4
+ // ---------------------------------------------------------------------------
5
+ // Tool sub-schemas
6
+ // ---------------------------------------------------------------------------
7
+ /** Handoff option within a transfer (prompt the receiving agent, etc.). */
8
+ const HandoffOptionSchema = z.object({
9
+ type: z.string().optional(),
10
+ prompt: z.string().optional(),
11
+ });
12
+ /** Transfer destination configuration. */
13
+ export const TransferDestinationSchema = z.object({
14
+ type: z.string().optional(),
15
+ prompt: z.string().optional(),
16
+ number: z.string().optional(),
17
+ extension: z.string().optional(),
18
+ });
19
+ /** Transfer option configuration (warm/cold transfer behavior). */
20
+ export const TransferOptionSchema = z.object({
21
+ type: z.string().optional(),
22
+ option: HandoffOptionSchema.optional(),
23
+ public_handoff_option: HandoffOptionSchema.optional(),
24
+ private_handoff_option: HandoffOptionSchema.optional(),
25
+ on_hold_music: z.string().optional(),
26
+ opt_out_initial_message: z.boolean().optional(),
27
+ opt_out_human_detection: z.boolean().optional(),
28
+ agent_detection_timeout_ms: z.number().optional(),
29
+ show_transferee_as_caller: z.boolean().optional(),
30
+ enable_bridge_audio_cue: z.boolean().optional(),
31
+ });
32
+ // ---------------------------------------------------------------------------
33
+ // Tools & states
34
+ // ---------------------------------------------------------------------------
35
+ /**
36
+ * Schema for an LLM tool. Tools are highly polymorphic (end_call,
37
+ * transfer_call, custom, cal, etc.) so we explicitly declare all known fields
38
+ * and use catchall to preserve any we haven't seen yet.
39
+ */
40
+ export const LlmToolSchema = z.object({
41
+ // Common
42
+ type: LlmToolTypeSchema,
43
+ name: z.string().optional(),
44
+ description: z.string().optional(),
45
+ tool_id: z.string().optional(),
46
+ // Custom tool HTTP config
47
+ url: z.string().optional(),
48
+ method: ToolHttpMethodSchema.optional(),
49
+ parameter_type: ToolParameterTypeSchema.optional(),
50
+ parameters: z.unknown().optional(),
51
+ headers: z.record(z.string(), z.string()).optional(),
52
+ query_params: z.record(z.string(), z.string()).optional(),
53
+ args_at_root: z.boolean().optional(),
54
+ timeout_ms: z.number().optional(),
55
+ response_variables: z.record(z.string(), z.string()).optional(),
56
+ // Speech behavior
57
+ speak_during_execution: z.boolean().optional(),
58
+ speak_after_execution: z.boolean().optional(),
59
+ execution_message_description: z.string().optional(),
60
+ // Transfer
61
+ transfer_destination: TransferDestinationSchema.optional(),
62
+ transfer_option: TransferOptionSchema.optional(),
63
+ custom_sip_headers: z.record(z.string(), z.string()).optional(),
64
+ // Cal.com integration
65
+ cal_api_key: z.string().optional(),
66
+ event_type_id: z.number().optional(),
67
+ timezone: z.string().optional(),
68
+ });
69
+ /** State transition edge within multi-prompt LLM. */
70
+ export const LlmStateEdgeSchema = z.object({
71
+ destination_state_name: z.string(),
72
+ description: z.string().optional(),
73
+ parameters: z.unknown().optional(),
74
+ });
75
+ /** A state within a multi-prompt LLM. */
76
+ export const LlmStateSchema = z.object({
77
+ name: z.string(),
78
+ state_prompt: z.string().optional(),
79
+ edges: z.array(LlmStateEdgeSchema).optional(),
80
+ tools: z.array(LlmToolSchema).nullable().optional(),
81
+ });
82
+ // ---------------------------------------------------------------------------
83
+ // LLM response
84
+ // ---------------------------------------------------------------------------
85
+ /** Zod schema for a Retell LLM response from the API. */
86
+ export const LlmResponseSchema = z.object({
87
+ // Required
88
+ llm_id: z.string(),
89
+ last_modification_timestamp: z.number(),
90
+ // Version
91
+ version: z.number().optional(),
92
+ is_published: z.boolean().optional(),
93
+ // Model selection
94
+ model: LlmModelSchema.nullable().optional(),
95
+ s2s_model: S2sModelSchema.nullable().optional(),
96
+ model_temperature: z.number().optional(),
97
+ model_high_priority: z.boolean().nullable().optional(),
98
+ tool_call_strict_mode: z.boolean().nullable().optional(),
99
+ // Knowledge base
100
+ knowledge_base_ids: z.array(z.string()).nullable().optional(),
101
+ kb_config: KbConfigSchema.nullable().optional(),
102
+ // Conversation
103
+ start_speaker: StartSpeakerSchema.optional(),
104
+ begin_after_user_silence_ms: z.number().nullable().optional(),
105
+ begin_message: z.string().nullable().optional(),
106
+ general_prompt: z.string().nullable().optional(),
107
+ // Tools & states
108
+ general_tools: z.array(LlmToolSchema).nullable().optional(),
109
+ states: z.array(LlmStateSchema).nullable().optional(),
110
+ starting_state: z.string().nullable().optional(),
111
+ // Dynamic variables
112
+ default_dynamic_variables: z
113
+ .record(z.string(), z.string())
114
+ .nullable()
115
+ .optional(),
116
+ // MCP
117
+ mcps: z.array(McpConfigSchema).nullable().optional(),
118
+ });
@@ -0,0 +1,14 @@
1
+ /**
2
+ * Fetches all pages from a paginated Retell API list endpoint. The Retell API
3
+ * uses cursor-based pagination where the last item's ID and version are passed
4
+ * as the cursor for the next page.
5
+ */
6
+ export declare function retellPagination<T>(
7
+ /** The list API call, receiving pagination options. */
8
+ op: (opts: {
9
+ limit?: number;
10
+ pagination_key?: string;
11
+ pagination_key_version?: number;
12
+ }) => Promise<T[]>,
13
+ /** The property name used as the pagination key (e.g. "agent_id", "llm_id"). */
14
+ idKey: keyof T & string, limit?: number): Promise<T[]>;
@@ -0,0 +1,35 @@
1
+ /**
2
+ * Fetches all pages from a paginated Retell API list endpoint. The Retell API
3
+ * uses cursor-based pagination where the last item's ID and version are passed
4
+ * as the cursor for the next page.
5
+ */
6
+ export async function retellPagination(
7
+ /** The list API call, receiving pagination options. */
8
+ op,
9
+ /** The property name used as the pagination key (e.g. "agent_id", "llm_id"). */
10
+ idKey, limit = 1000) {
11
+ const results = [];
12
+ let paginationKey;
13
+ let paginationKeyVersion;
14
+ while (true) {
15
+ const page = await op({
16
+ limit,
17
+ pagination_key: paginationKey,
18
+ pagination_key_version: paginationKeyVersion,
19
+ });
20
+ for (const item of page)
21
+ results.push(item);
22
+ if (page.length < limit)
23
+ break;
24
+ const lastItem = page.at(-1);
25
+ if (!lastItem)
26
+ break;
27
+ const id = lastItem[idKey];
28
+ if (typeof id !== "string")
29
+ break;
30
+ paginationKey = id;
31
+ const version = lastItem.version;
32
+ paginationKeyVersion = typeof version === "number" ? version : undefined;
33
+ }
34
+ return results;
35
+ }
@@ -0,0 +1,38 @@
1
+ import { z } from "zod";
2
+ /** Weighted agent entry used in phone number inbound/outbound lists. */
3
+ export declare const PhoneNumberAgentEntrySchema: z.ZodObject<{
4
+ agent_id: z.ZodString;
5
+ agent_version: z.ZodOptional<z.ZodNumber>;
6
+ weight: z.ZodNumber;
7
+ }, z.core.$strip>;
8
+ /** Zod schema for a phone number response from the Retell API. */
9
+ export declare const PhoneNumberResponseSchema: z.ZodObject<{
10
+ phone_number: z.ZodString;
11
+ phone_number_type: z.ZodOptional<z.ZodEnum<{
12
+ custom: "custom";
13
+ "retell-twilio": "retell-twilio";
14
+ "retell-telnyx": "retell-telnyx";
15
+ }>>;
16
+ nickname: z.ZodOptional<z.ZodNullable<z.ZodString>>;
17
+ last_modification_timestamp: z.ZodNumber;
18
+ inbound_agents: z.ZodOptional<z.ZodNullable<z.ZodArray<z.ZodObject<{
19
+ agent_id: z.ZodString;
20
+ agent_version: z.ZodOptional<z.ZodNumber>;
21
+ weight: z.ZodNumber;
22
+ }, z.core.$strip>>>>;
23
+ outbound_agents: z.ZodOptional<z.ZodNullable<z.ZodArray<z.ZodObject<{
24
+ agent_id: z.ZodString;
25
+ agent_version: z.ZodOptional<z.ZodNumber>;
26
+ weight: z.ZodNumber;
27
+ }, z.core.$strip>>>>;
28
+ inbound_sms_agents: z.ZodOptional<z.ZodNullable<z.ZodArray<z.ZodObject<{
29
+ agent_id: z.ZodString;
30
+ agent_version: z.ZodOptional<z.ZodNumber>;
31
+ weight: z.ZodNumber;
32
+ }, z.core.$strip>>>>;
33
+ outbound_sms_agents: z.ZodOptional<z.ZodNullable<z.ZodArray<z.ZodObject<{
34
+ agent_id: z.ZodString;
35
+ agent_version: z.ZodOptional<z.ZodNumber>;
36
+ weight: z.ZodNumber;
37
+ }, z.core.$strip>>>>;
38
+ }, z.core.$strip>;
@@ -0,0 +1,26 @@
1
+ import { z } from "zod";
2
+ /** Weighted agent entry used in phone number inbound/outbound lists. */
3
+ export const PhoneNumberAgentEntrySchema = z.object({
4
+ agent_id: z.string(),
5
+ agent_version: z.number().optional(),
6
+ weight: z.number(),
7
+ });
8
+ /** Zod schema for a phone number response from the Retell API. */
9
+ export const PhoneNumberResponseSchema = z.object({
10
+ phone_number: z.string(),
11
+ phone_number_type: z
12
+ .enum(["retell-twilio", "retell-telnyx", "custom"])
13
+ .optional(),
14
+ nickname: z.string().nullable().optional(),
15
+ last_modification_timestamp: z.number(),
16
+ inbound_agents: z.array(PhoneNumberAgentEntrySchema).nullable().optional(),
17
+ outbound_agents: z.array(PhoneNumberAgentEntrySchema).nullable().optional(),
18
+ inbound_sms_agents: z
19
+ .array(PhoneNumberAgentEntrySchema)
20
+ .nullable()
21
+ .optional(),
22
+ outbound_sms_agents: z
23
+ .array(PhoneNumberAgentEntrySchema)
24
+ .nullable()
25
+ .optional(),
26
+ });
package/dist/phone.d.ts CHANGED
@@ -1,8 +1,11 @@
1
1
  import { z } from "zod";
2
- /** Validates an international E.164 phone number (`+` followed by 1–15 digits). */
3
- export declare const E164PhoneSchema: z.ZodString;
2
+ /**
3
+ * Validates and normalizes a phone number to E.164 format (`+` followed by 1–15
4
+ * digits).
5
+ */
6
+ export declare const e164PhoneSchema: z.ZodPipe<z.ZodPipe<z.ZodString, z.ZodTransform<string | undefined, string>>, z.ZodString>;
4
7
  /**
5
8
  * E.164 phone number or null. Invalid, empty, or missing numbers are caught as
6
9
  * null — useful for `from_number` where caller ID may be unavailable.
7
10
  */
8
- export declare const e164OrNullSchema: z.ZodCatch<z.ZodNullable<z.ZodString>>;
11
+ export declare const e164OrNullSchema: z.ZodCatch<z.ZodNullable<z.ZodPipe<z.ZodPipe<z.ZodString, z.ZodTransform<string | undefined, string>>, z.ZodString>>>;
package/dist/phone.js CHANGED
@@ -1,8 +1,15 @@
1
1
  import { z } from "zod";
2
- /** Validates an international E.164 phone number (`+` followed by 1–15 digits). */
3
- export const E164PhoneSchema = z.string().regex(/^\+[1-9]\d{1,14}$/);
2
+ import { parsePhoneNumberFromString } from "libphonenumber-js";
3
+ /**
4
+ * Validates and normalizes a phone number to E.164 format (`+` followed by 1–15
5
+ * digits).
6
+ */
7
+ export const e164PhoneSchema = z
8
+ .string()
9
+ .transform((v) => parsePhoneNumberFromString(v, "US")?.format("E.164"))
10
+ .pipe(z.string().regex(/^\+[1-9]\d{1,14}$/));
4
11
  /**
5
12
  * E.164 phone number or null. Invalid, empty, or missing numbers are caught as
6
13
  * null — useful for `from_number` where caller ID may be unavailable.
7
14
  */
8
- export const e164OrNullSchema = E164PhoneSchema.nullable().catch(null);
15
+ export const e164OrNullSchema = e164PhoneSchema.nullable().catch(null);
@@ -0,0 +1,76 @@
1
+ import { z } from "zod";
2
+ /** Zod schema for input match rule types in test case tool mocks. */
3
+ export declare const InputMatchRuleSchema: z.ZodDiscriminatedUnion<[z.ZodObject<{
4
+ type: z.ZodLiteral<"any">;
5
+ }, z.core.$strip>, z.ZodObject<{
6
+ type: z.ZodLiteral<"partial_match">;
7
+ args: z.ZodRecord<z.ZodString, z.ZodUnknown>;
8
+ }, z.core.$strip>], "type">;
9
+ /** Zod schema for tool mock configurations in test cases. */
10
+ export declare const ToolMockSchema: z.ZodObject<{
11
+ tool_name: z.ZodString;
12
+ input_match_rule: z.ZodDiscriminatedUnion<[z.ZodObject<{
13
+ type: z.ZodLiteral<"any">;
14
+ }, z.core.$strip>, z.ZodObject<{
15
+ type: z.ZodLiteral<"partial_match">;
16
+ args: z.ZodRecord<z.ZodString, z.ZodUnknown>;
17
+ }, z.core.$strip>], "type">;
18
+ output: z.ZodString;
19
+ result: z.ZodOptional<z.ZodNullable<z.ZodBoolean>>;
20
+ }, z.core.$strip>;
21
+ /** Zod schema for response engine references in test cases. */
22
+ export declare const TestCaseResponseEngineSchema: z.ZodDiscriminatedUnion<[z.ZodObject<{
23
+ type: z.ZodLiteral<"retell-llm">;
24
+ llm_id: z.ZodString;
25
+ version: z.ZodOptional<z.ZodNumber>;
26
+ }, z.core.$strip>, z.ZodObject<{
27
+ type: z.ZodLiteral<"conversation-flow">;
28
+ conversation_flow_id: z.ZodString;
29
+ version: z.ZodOptional<z.ZodNumber>;
30
+ }, z.core.$strip>], "type">;
31
+ /** Zod schema for a test case definition from the Retell API. */
32
+ export declare const TestCaseDefinitionSchema: z.ZodObject<{
33
+ test_case_definition_id: z.ZodString;
34
+ name: z.ZodString;
35
+ response_engine: z.ZodDiscriminatedUnion<[z.ZodObject<{
36
+ type: z.ZodLiteral<"retell-llm">;
37
+ llm_id: z.ZodString;
38
+ version: z.ZodOptional<z.ZodNumber>;
39
+ }, z.core.$strip>, z.ZodObject<{
40
+ type: z.ZodLiteral<"conversation-flow">;
41
+ conversation_flow_id: z.ZodString;
42
+ version: z.ZodOptional<z.ZodNumber>;
43
+ }, z.core.$strip>], "type">;
44
+ dynamic_variables: z.ZodDefault<z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodUnknown>>>;
45
+ metrics: z.ZodDefault<z.ZodOptional<z.ZodArray<z.ZodString>>>;
46
+ user_prompt: z.ZodString;
47
+ creation_timestamp: z.ZodNumber;
48
+ user_modified_timestamp: z.ZodNumber;
49
+ type: z.ZodLiteral<"simulation">;
50
+ tool_mocks: z.ZodDefault<z.ZodOptional<z.ZodArray<z.ZodObject<{
51
+ tool_name: z.ZodString;
52
+ input_match_rule: z.ZodDiscriminatedUnion<[z.ZodObject<{
53
+ type: z.ZodLiteral<"any">;
54
+ }, z.core.$strip>, z.ZodObject<{
55
+ type: z.ZodLiteral<"partial_match">;
56
+ args: z.ZodRecord<z.ZodString, z.ZodUnknown>;
57
+ }, z.core.$strip>], "type">;
58
+ output: z.ZodString;
59
+ result: z.ZodOptional<z.ZodNullable<z.ZodBoolean>>;
60
+ }, z.core.$strip>>>>;
61
+ llm_model: z.ZodEnum<{
62
+ "gpt-4.1": "gpt-4.1";
63
+ "gpt-4.1-mini": "gpt-4.1-mini";
64
+ "gpt-4.1-nano": "gpt-4.1-nano";
65
+ "gpt-5": "gpt-5";
66
+ "gpt-5.1": "gpt-5.1";
67
+ "gpt-5.2": "gpt-5.2";
68
+ "gpt-5-mini": "gpt-5-mini";
69
+ "gpt-5-nano": "gpt-5-nano";
70
+ "claude-4.5-sonnet": "claude-4.5-sonnet";
71
+ "claude-4.5-haiku": "claude-4.5-haiku";
72
+ "gemini-2.5-flash": "gemini-2.5-flash";
73
+ "gemini-2.5-flash-lite": "gemini-2.5-flash-lite";
74
+ "gemini-3.0-flash": "gemini-3.0-flash";
75
+ }>;
76
+ }, z.core.$strip>;
@@ -0,0 +1,44 @@
1
+ import { z } from "zod";
2
+ import { LlmModelSchema } from "./enums.js";
3
+ /** Zod schema for input match rule types in test case tool mocks. */
4
+ export const InputMatchRuleSchema = z.discriminatedUnion("type", [
5
+ z.object({ type: z.literal("any") }),
6
+ z.object({
7
+ type: z.literal("partial_match"),
8
+ args: z.record(z.string(), z.unknown()),
9
+ }),
10
+ ]);
11
+ /** Zod schema for tool mock configurations in test cases. */
12
+ export const ToolMockSchema = z.object({
13
+ tool_name: z.string(),
14
+ input_match_rule: InputMatchRuleSchema,
15
+ output: z.string(),
16
+ result: z.boolean().nullable().optional(),
17
+ });
18
+ /** Zod schema for response engine references in test cases. */
19
+ export const TestCaseResponseEngineSchema = z.discriminatedUnion("type", [
20
+ z.object({
21
+ type: z.literal("retell-llm"),
22
+ llm_id: z.string(),
23
+ version: z.number().optional(),
24
+ }),
25
+ z.object({
26
+ type: z.literal("conversation-flow"),
27
+ conversation_flow_id: z.string(),
28
+ version: z.number().optional(),
29
+ }),
30
+ ]);
31
+ /** Zod schema for a test case definition from the Retell API. */
32
+ export const TestCaseDefinitionSchema = z.object({
33
+ test_case_definition_id: z.string(),
34
+ name: z.string(),
35
+ response_engine: TestCaseResponseEngineSchema,
36
+ dynamic_variables: z.record(z.string(), z.unknown()).optional().default({}),
37
+ metrics: z.array(z.string()).optional().default([]),
38
+ user_prompt: z.string(),
39
+ creation_timestamp: z.number(),
40
+ user_modified_timestamp: z.number(),
41
+ type: z.literal("simulation"),
42
+ tool_mocks: z.array(ToolMockSchema).optional().default([]),
43
+ llm_model: LlmModelSchema,
44
+ });
@@ -11,8 +11,8 @@ export declare const WordTimestampSchema: z.ZodObject<{
11
11
  */
12
12
  export declare const UtteranceSchema: z.ZodObject<{
13
13
  role: z.ZodEnum<{
14
- agent: "agent";
15
14
  user: "user";
15
+ agent: "agent";
16
16
  transfer_target: "transfer_target";
17
17
  }>;
18
18
  content: z.ZodString;
@@ -113,8 +113,8 @@ export declare const TranscriptEntrySchema: z.ZodDiscriminatedUnion<[z.ZodObject
113
113
  */
114
114
  export declare const TimestampedUtteranceSchema: z.ZodObject<{
115
115
  role: z.ZodEnum<{
116
- agent: "agent";
117
116
  user: "user";
117
+ agent: "agent";
118
118
  transfer_target: "transfer_target";
119
119
  }>;
120
120
  content: z.ZodString;
@@ -0,0 +1,18 @@
1
+ /** Converts a string to snake_case, stripping non-alphanumeric characters. */
2
+ export declare function toSnakeCase(str: string): string;
3
+ /**
4
+ * Simple English pluralizer. Handles common suffix rules (-y -> -ies, add -s).
5
+ * Optionally prefixes the quantity.
6
+ */
7
+ export declare function pluralize(word: string, q: number, includeQuantity?: boolean): string;
8
+ /**
9
+ * Recursively searches through an object/array structure and replaces `file://`
10
+ * placeholders with resolved file contents. Mutates the structure in place.
11
+ *
12
+ * @param resolveFileContent Called with the relative file path (after stripping
13
+ * the `file://` prefix) and should return the raw file content.
14
+ * @param transformContent Optional post-processor applied to each resolved
15
+ * file's content before it replaces the placeholder (e.g. strip YAML
16
+ * frontmatter from markdown).
17
+ */
18
+ export declare function resolveFilePlaceholders(value: unknown, resolveFileContent: (filePath: string) => string | Promise<string>, transformContent?: (content: string) => string | Promise<string>): Promise<void>;
package/dist/utils.js ADDED
@@ -0,0 +1,63 @@
1
+ /** Converts a string to snake_case, stripping non-alphanumeric characters. */
2
+ export function toSnakeCase(str) {
3
+ return str
4
+ .replace(/\s+/g, "_")
5
+ .replace(/([a-z0-9])([A-Z])/g, "$1_$2")
6
+ .replace(/[^a-z0-9_]/gi, "")
7
+ .toLowerCase()
8
+ .replace(/_+/g, "_")
9
+ .replace(/^_|_$/g, "");
10
+ }
11
+ /**
12
+ * Simple English pluralizer. Handles common suffix rules (-y -> -ies, add -s).
13
+ * Optionally prefixes the quantity.
14
+ */
15
+ export function pluralize(word, q, includeQuantity = false) {
16
+ let pluralWord = word;
17
+ if (q !== 1) {
18
+ if (word.endsWith("y") && !/[aeiou]y$/i.test(word)) {
19
+ pluralWord = `${word.slice(0, -1)}ies`;
20
+ }
21
+ else if (!word.endsWith("s")) {
22
+ pluralWord = `${word}s`;
23
+ }
24
+ }
25
+ const quantity = includeQuantity ? `${q} ` : "";
26
+ return `${quantity}${pluralWord}`;
27
+ }
28
+ /**
29
+ * Recursively searches through an object/array structure and replaces `file://`
30
+ * placeholders with resolved file contents. Mutates the structure in place.
31
+ *
32
+ * @param resolveFileContent Called with the relative file path (after stripping
33
+ * the `file://` prefix) and should return the raw file content.
34
+ * @param transformContent Optional post-processor applied to each resolved
35
+ * file's content before it replaces the placeholder (e.g. strip YAML
36
+ * frontmatter from markdown).
37
+ */
38
+ export async function resolveFilePlaceholders(value, resolveFileContent, transformContent) {
39
+ const resolveValue = async (val) => {
40
+ if (typeof val !== "string" || !val.startsWith("file://"))
41
+ return undefined;
42
+ const filePath = val.slice(7); // strip "file://"
43
+ const content = await resolveFileContent(filePath);
44
+ return transformContent ? transformContent(content) : content;
45
+ };
46
+ if (Array.isArray(value)) {
47
+ await Promise.all(value.map(async (item, i) => {
48
+ const resolved = await resolveValue(item);
49
+ if (resolved)
50
+ value[i] = resolved;
51
+ await resolveFilePlaceholders(item, resolveFileContent, transformContent);
52
+ }));
53
+ }
54
+ else if (value != null && typeof value === "object") {
55
+ const record = value;
56
+ await Promise.all(Object.entries(record).map(async ([key, propValue]) => {
57
+ const resolved = await resolveValue(propValue);
58
+ if (resolved)
59
+ record[key] = resolved;
60
+ await resolveFilePlaceholders(propValue, resolveFileContent, transformContent);
61
+ }));
62
+ }
63
+ }
package/dist/webhook.d.ts CHANGED
@@ -140,8 +140,8 @@ export declare const WebhookSchemas: {
140
140
  }, z.core.$strip>], "role">>>;
141
141
  }, z.core.$strip>, z.ZodDiscriminatedUnion<[z.ZodObject<{
142
142
  call_type: z.ZodLiteral<"phone_call">;
143
- from_number: z.ZodCatch<z.ZodNullable<z.ZodString>>;
144
- to_number: z.ZodString;
143
+ from_number: z.ZodCatch<z.ZodNullable<z.ZodPipe<z.ZodPipe<z.ZodString, z.ZodTransform<string | undefined, string>>, z.ZodString>>>;
144
+ to_number: z.ZodPipe<z.ZodPipe<z.ZodString, z.ZodTransform<string | undefined, string>>, z.ZodString>;
145
145
  direction: z.ZodEnum<{
146
146
  inbound: "inbound";
147
147
  outbound: "outbound";
@@ -231,8 +231,8 @@ export declare const WebhookSchemas: {
231
231
  }, z.core.$strip>], "role">>>;
232
232
  }, z.core.$strip>, z.ZodDiscriminatedUnion<[z.ZodObject<{
233
233
  call_type: z.ZodLiteral<"phone_call">;
234
- from_number: z.ZodCatch<z.ZodNullable<z.ZodString>>;
235
- to_number: z.ZodString;
234
+ from_number: z.ZodCatch<z.ZodNullable<z.ZodPipe<z.ZodPipe<z.ZodString, z.ZodTransform<string | undefined, string>>, z.ZodString>>>;
235
+ to_number: z.ZodPipe<z.ZodPipe<z.ZodString, z.ZodTransform<string | undefined, string>>, z.ZodString>;
236
236
  direction: z.ZodEnum<{
237
237
  inbound: "inbound";
238
238
  outbound: "outbound";
@@ -279,8 +279,8 @@ export declare const WebhookSchemas: {
279
279
  transcript: z.ZodOptional<z.ZodString>;
280
280
  transcript_object: z.ZodOptional<z.ZodArray<z.ZodObject<{
281
281
  role: z.ZodEnum<{
282
- agent: "agent";
283
282
  user: "user";
283
+ agent: "agent";
284
284
  transfer_target: "transfer_target";
285
285
  }>;
286
286
  content: z.ZodString;
@@ -515,8 +515,8 @@ export declare const WebhookSchemas: {
515
515
  }, z.core.$strip>], "role">>>;
516
516
  }, z.core.$strip>, z.ZodDiscriminatedUnion<[z.ZodObject<{
517
517
  call_type: z.ZodLiteral<"phone_call">;
518
- from_number: z.ZodCatch<z.ZodNullable<z.ZodString>>;
519
- to_number: z.ZodString;
518
+ from_number: z.ZodCatch<z.ZodNullable<z.ZodPipe<z.ZodPipe<z.ZodString, z.ZodTransform<string | undefined, string>>, z.ZodString>>>;
519
+ to_number: z.ZodPipe<z.ZodPipe<z.ZodString, z.ZodTransform<string | undefined, string>>, z.ZodString>;
520
520
  direction: z.ZodEnum<{
521
521
  inbound: "inbound";
522
522
  outbound: "outbound";
@@ -563,8 +563,8 @@ export declare const WebhookSchemas: {
563
563
  transcript: z.ZodOptional<z.ZodString>;
564
564
  transcript_object: z.ZodOptional<z.ZodArray<z.ZodObject<{
565
565
  role: z.ZodEnum<{
566
- agent: "agent";
567
566
  user: "user";
567
+ agent: "agent";
568
568
  transfer_target: "transfer_target";
569
569
  }>;
570
570
  content: z.ZodString;
@@ -968,8 +968,8 @@ export declare const WebhookSchemas: {
968
968
  }, z.core.$strip>], "role">>>;
969
969
  }, z.core.$strip>, z.ZodDiscriminatedUnion<[z.ZodObject<{
970
970
  call_type: z.ZodLiteral<"phone_call">;
971
- from_number: z.ZodCatch<z.ZodNullable<z.ZodString>>;
972
- to_number: z.ZodString;
971
+ from_number: z.ZodCatch<z.ZodNullable<z.ZodPipe<z.ZodPipe<z.ZodString, z.ZodTransform<string | undefined, string>>, z.ZodString>>>;
972
+ to_number: z.ZodPipe<z.ZodPipe<z.ZodString, z.ZodTransform<string | undefined, string>>, z.ZodString>;
973
973
  direction: z.ZodEnum<{
974
974
  inbound: "inbound";
975
975
  outbound: "outbound";
@@ -1058,8 +1058,8 @@ export declare const WebhookSchemas: {
1058
1058
  }, z.core.$strip>], "role">>>;
1059
1059
  }, z.core.$strip>, z.ZodDiscriminatedUnion<[z.ZodObject<{
1060
1060
  call_type: z.ZodLiteral<"phone_call">;
1061
- from_number: z.ZodCatch<z.ZodNullable<z.ZodString>>;
1062
- to_number: z.ZodString;
1061
+ from_number: z.ZodCatch<z.ZodNullable<z.ZodPipe<z.ZodPipe<z.ZodString, z.ZodTransform<string | undefined, string>>, z.ZodString>>>;
1062
+ to_number: z.ZodPipe<z.ZodPipe<z.ZodString, z.ZodTransform<string | undefined, string>>, z.ZodString>;
1063
1063
  direction: z.ZodEnum<{
1064
1064
  inbound: "inbound";
1065
1065
  outbound: "outbound";
@@ -1106,8 +1106,8 @@ export declare const WebhookSchemas: {
1106
1106
  transcript: z.ZodOptional<z.ZodString>;
1107
1107
  transcript_object: z.ZodOptional<z.ZodArray<z.ZodObject<{
1108
1108
  role: z.ZodEnum<{
1109
- agent: "agent";
1110
1109
  user: "user";
1110
+ agent: "agent";
1111
1111
  transfer_target: "transfer_target";
1112
1112
  }>;
1113
1113
  content: z.ZodString;
@@ -1341,8 +1341,8 @@ export declare const WebhookSchemas: {
1341
1341
  }, z.core.$strip>], "role">>>;
1342
1342
  }, z.core.$strip>, z.ZodDiscriminatedUnion<[z.ZodObject<{
1343
1343
  call_type: z.ZodLiteral<"phone_call">;
1344
- from_number: z.ZodCatch<z.ZodNullable<z.ZodString>>;
1345
- to_number: z.ZodString;
1344
+ from_number: z.ZodCatch<z.ZodNullable<z.ZodPipe<z.ZodPipe<z.ZodString, z.ZodTransform<string | undefined, string>>, z.ZodString>>>;
1345
+ to_number: z.ZodPipe<z.ZodPipe<z.ZodString, z.ZodTransform<string | undefined, string>>, z.ZodString>;
1346
1346
  direction: z.ZodEnum<{
1347
1347
  inbound: "inbound";
1348
1348
  outbound: "outbound";
@@ -1389,8 +1389,8 @@ export declare const WebhookSchemas: {
1389
1389
  transcript: z.ZodOptional<z.ZodString>;
1390
1390
  transcript_object: z.ZodOptional<z.ZodArray<z.ZodObject<{
1391
1391
  role: z.ZodEnum<{
1392
- agent: "agent";
1393
1392
  user: "user";
1393
+ agent: "agent";
1394
1394
  transfer_target: "transfer_target";
1395
1395
  }>;
1396
1396
  content: z.ZodString;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "retell-utils",
3
- "version": "0.3.2",
3
+ "version": "0.4.0",
4
4
  "description": "Type-safe Zod schemas for Retell AI API resources with lifecycle-aware discriminated unions and generic customization",
5
5
  "type": "module",
6
6
  "zshy": {
@@ -17,8 +17,9 @@
17
17
  "test": "bun test",
18
18
  "prepublishOnly": "bun run build"
19
19
  },
20
- "peerDependencies": {
21
- "zod": "^4.0.0"
20
+ "dependencies": {
21
+ "libphonenumber-js": "^1.12.36",
22
+ "zod": "^4.3.5"
22
23
  },
23
24
  "devDependencies": {
24
25
  "@types/bun": "latest",
@@ -27,7 +28,6 @@
27
28
  "prettier": "latest",
28
29
  "prettier-plugin-jsdoc": "^1.8.0",
29
30
  "typescript": "^5.8.3",
30
- "zod": "^4.3.5",
31
31
  "zshy": "^0.7.0"
32
32
  },
33
33
  "license": "MIT",