retell-sync-cli 3.7.2 → 3.8.1

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.
Files changed (2) hide show
  1. package/dist/cli.js +159 -10
  2. package/package.json +1 -1
package/dist/cli.js CHANGED
@@ -98673,6 +98673,9 @@ function diff(obj, newObj, options = { cyclesFix: true }, _stack = []) {
98673
98673
  return diffs;
98674
98674
  }
98675
98675
 
98676
+ // src/commands/deploy.ts
98677
+ import path17 from "path";
98678
+
98676
98679
  // node_modules/remeda/dist/lazyDataLastImpl-BDhrIOwR.js
98677
98680
  function e(e2, t, n) {
98678
98681
  let r = (n2) => e2(n2, ...t);
@@ -135140,19 +135143,15 @@ async function canonicalizeFromFiles(files) {
135140
135143
  var InputMatchRuleSchema = zod_default.discriminatedUnion("type", [
135141
135144
  zod_default.object({ type: zod_default.literal("any") }),
135142
135145
  zod_default.object({
135143
- type: zod_default.literal("exact"),
135144
- input: zod_default.record(zod_default.string(), zod_default.unknown())
135145
- }),
135146
- zod_default.object({
135147
- type: zod_default.literal("partial"),
135148
- input: zod_default.record(zod_default.string(), zod_default.unknown())
135146
+ type: zod_default.literal("partial_match"),
135147
+ args: zod_default.record(zod_default.string(), zod_default.unknown())
135149
135148
  })
135150
135149
  ]);
135151
135150
  var ToolMockSchema = zod_default.object({
135152
135151
  tool_name: zod_default.string(),
135153
135152
  input_match_rule: InputMatchRuleSchema,
135154
135153
  output: zod_default.string(),
135155
- result: zod_default.boolean()
135154
+ result: zod_default.boolean().nullable().optional()
135156
135155
  });
135157
135156
  var TestCaseResponseEngineSchema = zod_default.discriminatedUnion("type", [
135158
135157
  zod_default.object({
@@ -135213,6 +135212,73 @@ async function getTestCaseDefinitions(responseEngine) {
135213
135212
  }
135214
135213
  return result.data;
135215
135214
  }
135215
+ function canonicalizeTestCases(testCases) {
135216
+ return testCases.map(({ test_case_definition_id, response_engine: _10, ...rest }) => ({
135217
+ ...rest,
135218
+ _id: test_case_definition_id
135219
+ }));
135220
+ }
135221
+ async function getLocalTestCases(agentDirPath) {
135222
+ const testsDir = path15.join(agentDirPath, "tests");
135223
+ const metaFile = Bun.file(path15.join(testsDir, ".tests.json"));
135224
+ if (!await metaFile.exists()) {
135225
+ return [];
135226
+ }
135227
+ const metaContent = await metaFile.text();
135228
+ const metadata = await readJson2(metaContent, zod_default.object({
135229
+ response_engine: zod_default.object({}).passthrough(),
135230
+ test_cases: zod_default.array(zod_default.object({
135231
+ id: zod_default.string(),
135232
+ name: zod_default.string()
135233
+ }))
135234
+ }));
135235
+ const testCases = [];
135236
+ for (const testCaseMeta of metadata.test_cases) {
135237
+ const testCaseName = toSnakeCase(testCaseMeta.name);
135238
+ let configContent = null;
135239
+ let reader = readYaml;
135240
+ for (const ext of ["yaml", "yml", "jsonc", "json"]) {
135241
+ const configPath = path15.join(testsDir, `${testCaseName}.${ext}`);
135242
+ const file2 = Bun.file(configPath);
135243
+ if (await file2.exists()) {
135244
+ configContent = await file2.text();
135245
+ reader = ext === "jsonc" ? readJsonc : ext === "json" ? readJson2 : readYaml;
135246
+ break;
135247
+ }
135248
+ }
135249
+ if (!configContent) {
135250
+ console.warn(`Warning: Could not find config file for test case ${testCaseMeta.name}`);
135251
+ continue;
135252
+ }
135253
+ const config2 = await reader(configContent, zod_default.looseObject({}));
135254
+ const resolveFileContent = async (filePath) => {
135255
+ const normalizedPath = filePath.replace(/^\.\//, "");
135256
+ const fullPath = path15.join(testsDir, normalizedPath);
135257
+ const content = await Bun.file(fullPath).text();
135258
+ return content;
135259
+ };
135260
+ await resolveFilePlaceholders(config2, resolveFileContent);
135261
+ testCases.push({
135262
+ ...config2,
135263
+ _id: testCaseMeta.id
135264
+ });
135265
+ }
135266
+ return testCases;
135267
+ }
135268
+ async function updateTestCaseDefinition(testCaseId, update) {
135269
+ const response = await fetch(`https://api.retellai.com/update-test-case-definition/${testCaseId}`, {
135270
+ method: "PUT",
135271
+ headers: {
135272
+ Authorization: `Bearer ${process.env.RETELL_API_KEY}`,
135273
+ "Content-Type": "application/json"
135274
+ },
135275
+ body: JSON.stringify(update)
135276
+ });
135277
+ if (!response.ok) {
135278
+ const errorText = await response.text();
135279
+ throw new Error(`Failed to update test case ${testCaseId}: ${response.status} ${errorText}`);
135280
+ }
135281
+ }
135216
135282
  async function fetchAndWriteTestCases({
135217
135283
  state,
135218
135284
  agentsDir = DEFAULT_AGENTS_DIR,
@@ -135806,10 +135872,78 @@ async function deploy({
135806
135872
  const totalRemoteAgents = remoteState.voiceAgents.length + remoteState.chatAgents.length;
135807
135873
  spinner.stop(source_default.dim(`Local: ${totalLocalAgents} agents | Remote: ${totalRemoteAgents} agents`));
135808
135874
  spinner = createSpinner2("Computing differences...");
135809
- const changes = computeChanges(localState, remoteState);
135875
+ const baseChanges = computeChanges(localState, remoteState);
135876
+ const testCaseChanges = [];
135877
+ const allAgents = [
135878
+ ...localState.voiceAgents.map((a7) => ({
135879
+ ...a7,
135880
+ agentType: "voice"
135881
+ })),
135882
+ ...localState.chatAgents.map((a7) => ({ ...a7, agentType: "chat" }))
135883
+ ];
135884
+ for (const agent of allAgents) {
135885
+ if (agent.response_engine.type !== "retell-llm" && agent.response_engine.type !== "conversation-flow") {
135886
+ continue;
135887
+ }
135888
+ const agentName = agent.agent_name ?? agent._id;
135889
+ const hash2 = agent._id.slice(-FILE_HASH_LENGTH);
135890
+ const agentDirName = `${toSnakeCase(agentName)}_${hash2}`;
135891
+ const agentDirPath = path17.join(agentsDir, agentDirName);
135892
+ const localTestCases = await getLocalTestCases(agentDirPath);
135893
+ if (localTestCases.length === 0)
135894
+ continue;
135895
+ const normalizedEngine = agent.response_engine.type === "retell-llm" ? {
135896
+ type: "retell-llm",
135897
+ llm_id: agent.response_engine.llm_id,
135898
+ version: agent.response_engine.version ?? undefined
135899
+ } : {
135900
+ type: "conversation-flow",
135901
+ conversation_flow_id: agent.response_engine.conversation_flow_id,
135902
+ version: agent.response_engine.version ?? undefined
135903
+ };
135904
+ let remoteTestCases = [];
135905
+ try {
135906
+ const rawRemote = await getTestCaseDefinitions(normalizedEngine);
135907
+ remoteTestCases = canonicalizeTestCases(rawRemote);
135908
+ } catch {
135909
+ continue;
135910
+ }
135911
+ const testCaseMetadataFields = [
135912
+ "_id",
135913
+ "creation_timestamp",
135914
+ "user_modified_timestamp",
135915
+ "type"
135916
+ ];
135917
+ const remoteTestCaseMap = new Map(remoteTestCases.map((tc3) => [tc3._id, tc3]));
135918
+ for (const localTC of localTestCases) {
135919
+ const remoteTC = remoteTestCaseMap.get(localTC._id);
135920
+ if (!remoteTC)
135921
+ continue;
135922
+ const normalizePrompt = (s5) => s5.trim().replace(/\r\n/g, `
135923
+ `);
135924
+ const localComparable = {
135925
+ ...n9(localTC, testCaseMetadataFields),
135926
+ user_prompt: normalizePrompt(localTC.user_prompt)
135927
+ };
135928
+ const remoteComparable = {
135929
+ ...n9(remoteTC, testCaseMetadataFields),
135930
+ user_prompt: normalizePrompt(remoteTC.user_prompt)
135931
+ };
135932
+ const differences = diff(remoteComparable, localComparable);
135933
+ if (differences.length > 0) {
135934
+ testCaseChanges.push({
135935
+ id: localTC._id,
135936
+ name: localTC.name,
135937
+ current: localTC,
135938
+ differences
135939
+ });
135940
+ }
135941
+ }
135942
+ }
135943
+ const changes = { ...baseChanges, testCases: testCaseChanges };
135810
135944
  const totalAgentChanges = changes.voiceAgents.length + changes.chatAgents.length;
135811
- spinner.stop(source_default.dim(`Found ${source_default.white(totalAgentChanges)} agent changes, ${source_default.white(changes.llms.length)} LLM changes, ${source_default.white(changes.flows.length)} flow changes`));
135812
- const totalChanges = totalAgentChanges + changes.llms.length + changes.flows.length;
135945
+ spinner.stop(source_default.dim(`Found ${source_default.white(totalAgentChanges)} agent changes, ${source_default.white(changes.llms.length)} LLM changes, ${source_default.white(changes.flows.length)} flow changes, ${source_default.white(changes.testCases.length)} test case changes`));
135946
+ const totalChanges = totalAgentChanges + changes.llms.length + changes.flows.length + changes.testCases.length;
135813
135947
  const affectedAgentIds = new Set;
135814
135948
  for (const change of changes.voiceAgents) {
135815
135949
  affectedAgentIds.add(change.id);
@@ -135869,6 +136003,11 @@ async function deploy({
135869
136003
  const { _id, _version, ...updateData } = change.current;
135870
136004
  await retell.conversationFlow.update(_id, updateData);
135871
136005
  return { type: "flow", id: _id, name: change.name };
136006
+ }),
136007
+ ...changes.testCases.map(async (change) => {
136008
+ const { _id, ...updateData } = change.current;
136009
+ await updateTestCaseDefinition(_id, updateData);
136010
+ return { type: "test case", id: _id, name: change.name };
135872
136011
  })
135873
136012
  ]);
135874
136013
  spinner.stop(source_default.dim("Done"));
@@ -136060,6 +136199,16 @@ Flows to update:`));
136060
136199
  }
136061
136200
  }
136062
136201
  }
136202
+ if (changes.testCases.length > 0) {
136203
+ console.log(source_default.cyan(`
136204
+ Test cases to update:`));
136205
+ for (const change of changes.testCases) {
136206
+ console.log(` ${source_default.bold(change.name)} ${source_default.dim(`(${change.id})`)}`);
136207
+ for (const d5 of change.differences) {
136208
+ printDiff(d5, { verbose });
136209
+ }
136210
+ }
136211
+ }
136063
136212
  }
136064
136213
 
136065
136214
  // src/commands/publish.ts
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "retell-sync-cli",
3
- "version": "3.7.2",
3
+ "version": "3.8.1",
4
4
  "description": "CLI tool for syncing Retell AI agents between local filesystem and API",
5
5
  "keywords": [
6
6
  "agents",