From de25669417b5b06d081dcd98b7e0459bb496f7dd Mon Sep 17 00:00:00 2001 From: Boris Starkov Date: Fri, 3 Apr 2026 16:37:02 +0100 Subject: [PATCH 1/2] fix: preserve model_usage keys from case conversion during test push Model name keys (e.g. gpt_5.2, gpt-4o-mini, gemini-2.5-flash) under model_usage are user-defined identifiers, not schema fields. The case conversion was mangling them (gpt_5.2 -> gpt5.2, gpt-4o-mini -> gpt4oMini), causing 422 validation errors on test push. Co-Authored-By: Claude Opus 4.6 (1M context) --- src/__tests__/utils.test.ts | 84 +++++++++++++++++++++++++++++++++++++ src/shared/utils.ts | 1 + 2 files changed, 85 insertions(+) diff --git a/src/__tests__/utils.test.ts b/src/__tests__/utils.test.ts index b85f514..2162660 100644 --- a/src/__tests__/utils.test.ts +++ b/src/__tests__/utils.test.ts @@ -824,6 +824,90 @@ describe("Utils", () => { expect(afterPull).toEqual(originalWorkflow); }); + it("should preserve model_usage keys in toCamelCaseKeys", () => { + const input = { + from_conversation_metadata: { + original_agent_reply: { + llm_usage: { + model_usage: { + "gpt_5.2": { input_tokens: 100, output_tokens: 50 }, + "gpt-4o-mini": { input_tokens: 200, output_tokens: 100 }, + "gemini-2.5-flash": { input_tokens: 300, output_tokens: 150 }, + "claude-3-opus": { input_tokens: 400, output_tokens: 200 } + } + } + } + } + }; + + const result = toCamelCaseKeys(input); + + expect(result).toEqual({ + fromConversationMetadata: { + originalAgentReply: { + llmUsage: { + modelUsage: { + "gpt_5.2": { inputTokens: 100, outputTokens: 50 }, // preserved - model name + "gpt-4o-mini": { inputTokens: 200, outputTokens: 100 }, // preserved - model name + "gemini-2.5-flash": { inputTokens: 300, outputTokens: 150 }, // preserved - model name + "claude-3-opus": { inputTokens: 400, outputTokens: 200 } // preserved - model name + } + } + } + } + }); + }); + + it("should preserve modelUsage keys in toSnakeCaseKeys", () => { + const input = { + fromConversationMetadata: { + originalAgentReply: { + llmUsage: { + modelUsage: { + "gpt-5.2": { inputTokens: 100, outputTokens: 50 }, + "gpt-4o-mini": { inputTokens: 200, outputTokens: 100 } + } + } + } + } + }; + + const result = toSnakeCaseKeys(input); + + expect(result).toEqual({ + from_conversation_metadata: { + original_agent_reply: { + llm_usage: { + model_usage: { + "gpt-5.2": { input_tokens: 100, output_tokens: 50 }, // preserved - model name + "gpt-4o-mini": { input_tokens: 200, output_tokens: 100 } // preserved - model name + } + } + } + } + }); + }); + + it("should maintain round-trip conversion symmetry for model_usage", () => { + const original = { + from_conversation_metadata: { + original_agent_reply: { + llm_usage: { + model_usage: { + "gpt_5.2": { input_tokens: 100, output_tokens: 50 }, + "gpt-4o-mini": { input_tokens: 200, output_tokens: 100 } + } + } + } + } + }; + + const afterPush = toCamelCaseKeys(original); + const afterPull = toSnakeCaseKeys(afterPush); + + expect(afterPull).toEqual(original); + }); + it("should maintain round-trip conversion symmetry for dynamic_variables", () => { // Simulate pull → push cycle for tests const originalTestConfig = { diff --git a/src/shared/utils.ts b/src/shared/utils.ts index cac2116..7ac85a6 100644 --- a/src/shared/utils.ts +++ b/src/shared/utils.ts @@ -124,6 +124,7 @@ const PRESERVE_CHILD_KEYS = new Set([ 'request_headers', 'requestHeaders', 'dynamic_variables', 'dynamicVariables', 'language_presets', 'languagePresets', + 'model_usage', 'modelUsage', 'nodes', 'edges', ]); From ccd2e0b3ed1a400ca70baf8e19eda1fce5f513fb Mon Sep 17 00:00:00 2001 From: Boris Starkov Date: Fri, 3 Apr 2026 16:54:02 +0100 Subject: [PATCH 2/2] 0.5.1 Co-Authored-By: Claude Opus 4.6 (1M context) --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index eac9973..6c9b9ce 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "@elevenlabs/cli", - "version": "0.5.0", + "version": "0.5.1", "description": "CLI tool to manage ElevenLabs agents", "type": "module", "keywords": [