Skip to content

fix: preserve data_collection child keys from case conversion (#70)#78

Merged
kraenhansen merged 3 commits into
elevenlabs:mainfrom
sined-rahkuk:fix/preserve-data-collection-keys
May 6, 2026
Merged

fix: preserve data_collection child keys from case conversion (#70)#78
kraenhansen merged 3 commits into
elevenlabs:mainfrom
sined-rahkuk:fix/preserve-data-collection-keys

Conversation

@sined-rahkuk
Copy link
Copy Markdown
Contributor

Summary

Adds data_collection / dataCollection to PRESERVE_CHILD_KEYS so its immediate children (user-defined identifiers like need_callback, call_end_reason, human_reached) are not silently rewritten to camelCase by toCamelCaseKeys on push or to snake_case by toSnakeCaseKeys on pull.

Closes #70.

Why

data_collection is the same class of construct as dynamic_variables, language_presets, model_usage, nodes, edges — its immediate children are user-defined identifiers that the platform stores verbatim. Case conversion is corrupting. In particular, the dashboard's callback-checkbox feature keys on the literal need_callback identifier; after a CLI push those show up on the platform as needCallback and the feature silently stops working.

Fix follows the same one-line pattern as the prior model_usage fix (#72) and language_presets fix (#65).

Test plan

Three new cases in src/__tests__/casing.test.ts:

  • createAgentApi preserves data_collection child keys (user-defined identifiers) — verifies platformSettings.dataCollection.need_callback (and siblings) survive outbound conversion with their exact original keys.
  • updateAgentApi preserves data_collection child keys (user-defined identifiers) — same assertion on the update path.
  • getAgentApi preserves data_collection child keys on inbound snake_case conversion — verifies the round-trip back to disk keeps children intact.

Reproduced the bug locally by running the new tests against main (2 of 3 fail: push-direction tests rewrite children to camelCase). With the fix, all 11 casing.test.ts cases pass.

No regressions: the pre-existing failures in tools.test.ts, add-commands-filename.integration.test.ts, and test-commands.integration.test.ts reproduce identically on main without this patch, so they are unrelated to this change.

…labs#70)

data_collection stores user-defined identifiers (e.g. need_callback,
call_end_reason, human_reached) that the ElevenLabs platform expects to
receive and return verbatim. Without preservation, toCamelCaseKeys
silently rewrote them to camelCase on push, which the platform stores
as-is and which breaks dashboard features that key on the original
snake_case identifiers (e.g. the callback checkbox feature driven by
need_callback).

Added data_collection and dataCollection to PRESERVE_CHILD_KEYS, so its
immediate children are passed through unchanged in both push and pull
directions.

Tests: three new cases in casing.test.ts cover create / update / get
round-trips. Verified that the existing failing reproduction fails
without the fix and passes with it. No regressions in the wider suite.

Fixes elevenlabs#70
Copy link
Copy Markdown

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull request overview

This PR updates the shared key-casing normalization utilities so data_collection / dataCollection is treated like other “user-defined identifier maps” (e.g., dynamic_variables, language_presets, model_usage), preventing case conversion from rewriting its immediate child keys during push/pull.

Changes:

  • Add data_collection / dataCollection to PRESERVE_CHILD_KEYS to prevent child-key case conversion.
  • Add unit tests covering push-path preservation for createAgentApi and updateAgentApi.
  • Add a unit test intended to cover pull-path preservation for getAgentApi.

Reviewed changes

Copilot reviewed 2 out of 2 changed files in this pull request and generated 1 comment.

File Description
src/shared/utils.ts Extends preserved-child-key handling to data_collection / dataCollection to avoid mutating user-defined identifiers during casing conversion.
src/tests/casing.test.ts Adds tests asserting data_collection child keys are preserved on create/update, plus an inbound (get) test intended to validate the pull path.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment on lines +366 to +392
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({
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.

kraenhansen and others added 2 commits May 6, 2026 11:52
…preservation logic

The inbound test was using snake_case child keys in the mock response,
which would pass even without PRESERVE_CHILD_KEYS. Changed one child
key to camelCase (callEndReason) and assert it stays camelCase — proving
the preservation logic prevents unwanted conversion to call_end_reason.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
…servation

The existing getAgentApi test uses snake_case child keys in the mock,
which pass trivially without PRESERVE_CHILD_KEYS. Add a separate test
with a camelCase child key (callEndReason) that asserts it is not
converted to call_end_reason on the inbound path.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Copy link
Copy Markdown
Member

@kraenhansen kraenhansen left a comment

Choose a reason for hiding this comment

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

LGTM — fix follows the established pattern. Added a test to cover the inbound camelCase case flagged by Copilot.

@kraenhansen kraenhansen merged commit e4f8db1 into elevenlabs:main May 6, 2026
@kraenhansen kraenhansen mentioned this pull request May 6, 2026
2 tasks
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

data_collection keys incorrectly converted to camelCase on push

3 participants