Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
121 changes: 121 additions & 0 deletions src/__tests__/casing.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -299,6 +299,127 @@ describe("Key casing normalization", () => {
});
});

it("createAgentApi preserves data_collection child keys (user-defined identifiers)", async () => {
const client = makeMockClient();
const conversation_config = {
agent: { prompt: { prompt: "hi", temperature: 0 } },
} as unknown as Record<string, unknown>;
const platform_settings = {
data_collection: {
need_callback: { type: "boolean", description: "Whether to call back" },
call_end_reason: { type: "string", description: "Why the call ended" },
human_reached: { type: "boolean", description: "Was a human reached" },
},
} as unknown as Record<string, unknown>;

await createAgentApi(
client,
"Agent with data_collection",
conversation_config,
platform_settings,
undefined,
[]
);

const payload = (client.conversationalAi.agents.create as jest.Mock).mock.calls[0][0];

// data_collection top-level key is camelized to dataCollection (envelope convention)
expect(payload.platformSettings).toHaveProperty("dataCollection");
// Children are user-defined identifiers — must be preserved as-is (snake_case stays snake_case)
expect(payload.platformSettings.dataCollection).toHaveProperty("need_callback");
expect(payload.platformSettings.dataCollection).toHaveProperty("call_end_reason");
expect(payload.platformSettings.dataCollection).toHaveProperty("human_reached");
// Leaf values under each identifier — nested schema fields like 'type'/'description' stay as-is (no underscores to convert)
expect(payload.platformSettings.dataCollection.need_callback).toEqual({
type: "boolean",
description: "Whether to call back",
});
});

it("updateAgentApi preserves data_collection child keys (user-defined identifiers)", async () => {
const client = makeMockClient();
const conversation_config = {
agent: { prompt: { prompt: "updated", temperature: 0 } },
} as unknown as Record<string, unknown>;
const platform_settings = {
data_collection: {
need_callback: { type: "boolean", description: "Callback requested" },
},
} as unknown as Record<string, unknown>;

await updateAgentApi(
client,
"agent_123",
"Updated",
conversation_config,
platform_settings,
undefined,
[]
);

const [, payload] = (client.conversationalAi.agents.update as jest.Mock).mock.calls[0];

expect(payload.platformSettings).toHaveProperty("dataCollection");
expect(payload.platformSettings.dataCollection).toHaveProperty("need_callback");
});

it("getAgentApi preserves data_collection child keys on inbound snake_case conversion", async () => {
const getWithDataCollection = jest.fn().mockResolvedValue({
agentId: "agent_123",
name: "Test",
conversationConfig: {
agent: { prompt: { prompt: "hi", temperature: 0 } },
},
platformSettings: {
dataCollection: {
need_callback: { type: "boolean", description: "Callback" },
call_end_reason: { type: "string" },
},
},
tags: [],
});
const client = {
conversationalAi: { agents: { get: getWithDataCollection } },
} as unknown as ElevenLabsClient;

const response = await getAgentApi(client, "agent_123") as Record<string, any>;

// Envelope snake_cases back for disk
expect(response.platform_settings).toHaveProperty("data_collection");
// User-defined identifiers preserved as-is — no round-trip corruption
expect(response.platform_settings.data_collection).toHaveProperty("need_callback");
expect(response.platform_settings.data_collection).toHaveProperty("call_end_reason");
expect(response.platform_settings.data_collection.need_callback).toEqual({
Comment on lines +366 to +392
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Addressed in 303dac1 — added a separate test ("getAgentApi does not snake_case camelCase data_collection child keys") that uses a camelCase mock key and asserts it isn't converted.

type: "boolean",
description: "Callback",
});
});

it("getAgentApi does not snake_case camelCase data_collection child keys", async () => {
const getWithDataCollection = jest.fn().mockResolvedValue({
agentId: "agent_123",
name: "Test",
conversationConfig: {
agent: { prompt: { prompt: "hi", temperature: 0 } },
},
platformSettings: {
dataCollection: {
callEndReason: { type: "string", description: "Why the call ended" },
},
},
tags: [],
});
const client = {
conversationalAi: { agents: { get: getWithDataCollection } },
} as unknown as ElevenLabsClient;

const response = await getAgentApi(client, "agent_123") as Record<string, any>;

expect(response.platform_settings).toHaveProperty("data_collection");
expect(response.platform_settings.data_collection).toHaveProperty("callEndReason");
expect(response.platform_settings.data_collection).not.toHaveProperty("call_end_reason");
});

it("createAgentApi preserves 'tools' field when 'tool_ids' is not present", async () => {
const client = makeMockClient();
const conversation_config = {
Expand Down
1 change: 1 addition & 0 deletions src/shared/utils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -125,6 +125,7 @@ const PRESERVE_CHILD_KEYS = new Set([
'dynamic_variables', 'dynamicVariables',
'language_presets', 'languagePresets',
'model_usage', 'modelUsage',
'data_collection', 'dataCollection',
'nodes',
'edges',
]);
Expand Down