retell-sync-cli 3.7.2 → 3.8.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/cli.js +156 -3
- 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);
|
|
@@ -135213,6 +135216,73 @@ async function getTestCaseDefinitions(responseEngine) {
|
|
|
135213
135216
|
}
|
|
135214
135217
|
return result.data;
|
|
135215
135218
|
}
|
|
135219
|
+
function canonicalizeTestCases(testCases) {
|
|
135220
|
+
return testCases.map(({ test_case_definition_id, response_engine: _10, ...rest }) => ({
|
|
135221
|
+
...rest,
|
|
135222
|
+
_id: test_case_definition_id
|
|
135223
|
+
}));
|
|
135224
|
+
}
|
|
135225
|
+
async function getLocalTestCases(agentDirPath) {
|
|
135226
|
+
const testsDir = path15.join(agentDirPath, "tests");
|
|
135227
|
+
const metaFile = Bun.file(path15.join(testsDir, ".tests.json"));
|
|
135228
|
+
if (!await metaFile.exists()) {
|
|
135229
|
+
return [];
|
|
135230
|
+
}
|
|
135231
|
+
const metaContent = await metaFile.text();
|
|
135232
|
+
const metadata = await readJson2(metaContent, zod_default.object({
|
|
135233
|
+
response_engine: zod_default.object({}).passthrough(),
|
|
135234
|
+
test_cases: zod_default.array(zod_default.object({
|
|
135235
|
+
id: zod_default.string(),
|
|
135236
|
+
name: zod_default.string()
|
|
135237
|
+
}))
|
|
135238
|
+
}));
|
|
135239
|
+
const testCases = [];
|
|
135240
|
+
for (const testCaseMeta of metadata.test_cases) {
|
|
135241
|
+
const testCaseName = toSnakeCase(testCaseMeta.name);
|
|
135242
|
+
let configContent = null;
|
|
135243
|
+
let reader = readYaml;
|
|
135244
|
+
for (const ext of ["yaml", "yml", "jsonc", "json"]) {
|
|
135245
|
+
const configPath = path15.join(testsDir, `${testCaseName}.${ext}`);
|
|
135246
|
+
const file2 = Bun.file(configPath);
|
|
135247
|
+
if (await file2.exists()) {
|
|
135248
|
+
configContent = await file2.text();
|
|
135249
|
+
reader = ext === "jsonc" ? readJsonc : ext === "json" ? readJson2 : readYaml;
|
|
135250
|
+
break;
|
|
135251
|
+
}
|
|
135252
|
+
}
|
|
135253
|
+
if (!configContent) {
|
|
135254
|
+
console.warn(`Warning: Could not find config file for test case ${testCaseMeta.name}`);
|
|
135255
|
+
continue;
|
|
135256
|
+
}
|
|
135257
|
+
const config2 = await reader(configContent, zod_default.looseObject({}));
|
|
135258
|
+
const resolveFileContent = async (filePath) => {
|
|
135259
|
+
const normalizedPath = filePath.replace(/^\.\//, "");
|
|
135260
|
+
const fullPath = path15.join(testsDir, normalizedPath);
|
|
135261
|
+
const content = await Bun.file(fullPath).text();
|
|
135262
|
+
return content;
|
|
135263
|
+
};
|
|
135264
|
+
await resolveFilePlaceholders(config2, resolveFileContent);
|
|
135265
|
+
testCases.push({
|
|
135266
|
+
...config2,
|
|
135267
|
+
_id: testCaseMeta.id
|
|
135268
|
+
});
|
|
135269
|
+
}
|
|
135270
|
+
return testCases;
|
|
135271
|
+
}
|
|
135272
|
+
async function updateTestCaseDefinition(testCaseId, update) {
|
|
135273
|
+
const response = await fetch(`https://api.retellai.com/update-test-case-definition/${testCaseId}`, {
|
|
135274
|
+
method: "PUT",
|
|
135275
|
+
headers: {
|
|
135276
|
+
Authorization: `Bearer ${process.env.RETELL_API_KEY}`,
|
|
135277
|
+
"Content-Type": "application/json"
|
|
135278
|
+
},
|
|
135279
|
+
body: JSON.stringify(update)
|
|
135280
|
+
});
|
|
135281
|
+
if (!response.ok) {
|
|
135282
|
+
const errorText = await response.text();
|
|
135283
|
+
throw new Error(`Failed to update test case ${testCaseId}: ${response.status} ${errorText}`);
|
|
135284
|
+
}
|
|
135285
|
+
}
|
|
135216
135286
|
async function fetchAndWriteTestCases({
|
|
135217
135287
|
state,
|
|
135218
135288
|
agentsDir = DEFAULT_AGENTS_DIR,
|
|
@@ -135806,10 +135876,78 @@ async function deploy({
|
|
|
135806
135876
|
const totalRemoteAgents = remoteState.voiceAgents.length + remoteState.chatAgents.length;
|
|
135807
135877
|
spinner.stop(source_default.dim(`Local: ${totalLocalAgents} agents | Remote: ${totalRemoteAgents} agents`));
|
|
135808
135878
|
spinner = createSpinner2("Computing differences...");
|
|
135809
|
-
const
|
|
135879
|
+
const baseChanges = computeChanges(localState, remoteState);
|
|
135880
|
+
const testCaseChanges = [];
|
|
135881
|
+
const allAgents = [
|
|
135882
|
+
...localState.voiceAgents.map((a7) => ({
|
|
135883
|
+
...a7,
|
|
135884
|
+
agentType: "voice"
|
|
135885
|
+
})),
|
|
135886
|
+
...localState.chatAgents.map((a7) => ({ ...a7, agentType: "chat" }))
|
|
135887
|
+
];
|
|
135888
|
+
for (const agent of allAgents) {
|
|
135889
|
+
if (agent.response_engine.type !== "retell-llm" && agent.response_engine.type !== "conversation-flow") {
|
|
135890
|
+
continue;
|
|
135891
|
+
}
|
|
135892
|
+
const agentName = agent.agent_name ?? agent._id;
|
|
135893
|
+
const hash2 = agent._id.slice(-FILE_HASH_LENGTH);
|
|
135894
|
+
const agentDirName = `${toSnakeCase(agentName)}_${hash2}`;
|
|
135895
|
+
const agentDirPath = path17.join(agentsDir, agentDirName);
|
|
135896
|
+
const localTestCases = await getLocalTestCases(agentDirPath);
|
|
135897
|
+
if (localTestCases.length === 0)
|
|
135898
|
+
continue;
|
|
135899
|
+
const normalizedEngine = agent.response_engine.type === "retell-llm" ? {
|
|
135900
|
+
type: "retell-llm",
|
|
135901
|
+
llm_id: agent.response_engine.llm_id,
|
|
135902
|
+
version: agent.response_engine.version ?? undefined
|
|
135903
|
+
} : {
|
|
135904
|
+
type: "conversation-flow",
|
|
135905
|
+
conversation_flow_id: agent.response_engine.conversation_flow_id,
|
|
135906
|
+
version: agent.response_engine.version ?? undefined
|
|
135907
|
+
};
|
|
135908
|
+
let remoteTestCases = [];
|
|
135909
|
+
try {
|
|
135910
|
+
const rawRemote = await getTestCaseDefinitions(normalizedEngine);
|
|
135911
|
+
remoteTestCases = canonicalizeTestCases(rawRemote);
|
|
135912
|
+
} catch {
|
|
135913
|
+
continue;
|
|
135914
|
+
}
|
|
135915
|
+
const testCaseMetadataFields = [
|
|
135916
|
+
"_id",
|
|
135917
|
+
"creation_timestamp",
|
|
135918
|
+
"user_modified_timestamp",
|
|
135919
|
+
"type"
|
|
135920
|
+
];
|
|
135921
|
+
const remoteTestCaseMap = new Map(remoteTestCases.map((tc3) => [tc3._id, tc3]));
|
|
135922
|
+
for (const localTC of localTestCases) {
|
|
135923
|
+
const remoteTC = remoteTestCaseMap.get(localTC._id);
|
|
135924
|
+
if (!remoteTC)
|
|
135925
|
+
continue;
|
|
135926
|
+
const normalizePrompt = (s5) => s5.trim().replace(/\r\n/g, `
|
|
135927
|
+
`);
|
|
135928
|
+
const localComparable = {
|
|
135929
|
+
...n9(localTC, testCaseMetadataFields),
|
|
135930
|
+
user_prompt: normalizePrompt(localTC.user_prompt)
|
|
135931
|
+
};
|
|
135932
|
+
const remoteComparable = {
|
|
135933
|
+
...n9(remoteTC, testCaseMetadataFields),
|
|
135934
|
+
user_prompt: normalizePrompt(remoteTC.user_prompt)
|
|
135935
|
+
};
|
|
135936
|
+
const differences = diff(remoteComparable, localComparable);
|
|
135937
|
+
if (differences.length > 0) {
|
|
135938
|
+
testCaseChanges.push({
|
|
135939
|
+
id: localTC._id,
|
|
135940
|
+
name: localTC.name,
|
|
135941
|
+
current: localTC,
|
|
135942
|
+
differences
|
|
135943
|
+
});
|
|
135944
|
+
}
|
|
135945
|
+
}
|
|
135946
|
+
}
|
|
135947
|
+
const changes = { ...baseChanges, testCases: testCaseChanges };
|
|
135810
135948
|
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;
|
|
135949
|
+
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`));
|
|
135950
|
+
const totalChanges = totalAgentChanges + changes.llms.length + changes.flows.length + changes.testCases.length;
|
|
135813
135951
|
const affectedAgentIds = new Set;
|
|
135814
135952
|
for (const change of changes.voiceAgents) {
|
|
135815
135953
|
affectedAgentIds.add(change.id);
|
|
@@ -135869,6 +136007,11 @@ async function deploy({
|
|
|
135869
136007
|
const { _id, _version, ...updateData } = change.current;
|
|
135870
136008
|
await retell.conversationFlow.update(_id, updateData);
|
|
135871
136009
|
return { type: "flow", id: _id, name: change.name };
|
|
136010
|
+
}),
|
|
136011
|
+
...changes.testCases.map(async (change) => {
|
|
136012
|
+
const { _id, ...updateData } = change.current;
|
|
136013
|
+
await updateTestCaseDefinition(_id, updateData);
|
|
136014
|
+
return { type: "test case", id: _id, name: change.name };
|
|
135872
136015
|
})
|
|
135873
136016
|
]);
|
|
135874
136017
|
spinner.stop(source_default.dim("Done"));
|
|
@@ -136060,6 +136203,16 @@ Flows to update:`));
|
|
|
136060
136203
|
}
|
|
136061
136204
|
}
|
|
136062
136205
|
}
|
|
136206
|
+
if (changes.testCases.length > 0) {
|
|
136207
|
+
console.log(source_default.cyan(`
|
|
136208
|
+
Test cases to update:`));
|
|
136209
|
+
for (const change of changes.testCases) {
|
|
136210
|
+
console.log(` ${source_default.bold(change.name)} ${source_default.dim(`(${change.id})`)}`);
|
|
136211
|
+
for (const d5 of change.differences) {
|
|
136212
|
+
printDiff(d5, { verbose });
|
|
136213
|
+
}
|
|
136214
|
+
}
|
|
136215
|
+
}
|
|
136063
136216
|
}
|
|
136064
136217
|
|
|
136065
136218
|
// src/commands/publish.ts
|