|
88 | 88 | ) |
89 | 89 | .variation_for_all(1)) |
90 | 90 |
|
| 91 | + data_source.update(data_source.flag('model-config-with-key-version') |
| 92 | + .variations( |
| 93 | + { |
| 94 | + model: { |
| 95 | + name: 'gpt-4', |
| 96 | + modelKey: 'my-model', |
| 97 | + modelVersion: 2, |
| 98 | + }, |
| 99 | + provider: { name: 'openai' }, |
| 100 | + messages: [], |
| 101 | + _ldMeta: { enabled: true, variationKey: 'v1', version: 1 }, |
| 102 | + } |
| 103 | + ) |
| 104 | + .variation_for_all(0)) |
| 105 | + |
91 | 106 | data_source |
92 | 107 | end |
93 | 108 |
|
|
113 | 128 | expect(model.custom('non-existent')).to be_nil |
114 | 129 | expect(model.custom('name')).to be_nil |
115 | 130 | end |
| 131 | + |
| 132 | + it 'to_h omits modelKey and modelVersion when unset' do |
| 133 | + model = described_class.new(name: 'fakeModel', parameters: { temperature: 0.5 }) |
| 134 | + expect(model.model_key).to be_nil |
| 135 | + expect(model.model_version).to be_nil |
| 136 | + result = model.to_h |
| 137 | + expect(result).not_to have_key(:modelKey) |
| 138 | + expect(result).not_to have_key(:modelVersion) |
| 139 | + end |
| 140 | + |
| 141 | + it 'to_h includes modelKey and modelVersion when set' do |
| 142 | + model = described_class.new(name: 'fakeModel', model_key: 'my-model', model_version: 2) |
| 143 | + result = model.to_h |
| 144 | + expect(result[:modelKey]).to eq('my-model') |
| 145 | + expect(result[:modelVersion]).to eq(2) |
| 146 | + end |
| 147 | + |
| 148 | + it 'to_h omits empty modelKey' do |
| 149 | + model = described_class.new(name: 'fakeModel', model_key: '') |
| 150 | + result = model.to_h |
| 151 | + expect(result).not_to have_key(:modelKey) |
| 152 | + end |
116 | 153 | end |
117 | 154 |
|
118 | 155 | describe LaunchDarkly::Server::AI::Client do |
|
408 | 445 | expect(flag_data[:version]).to eq(1) |
409 | 446 | expect(flag_data[:modelName]).to eq('fakeModel') |
410 | 447 | expect(flag_data[:providerName]).to eq('fakeProvider') |
| 448 | + expect(flag_data[:modelVersion]).to eq(1) |
| 449 | + expect(flag_data).not_to have_key(:modelKey) |
| 450 | + end |
| 451 | + |
| 452 | + it 'reads modelKey and modelVersion from flag payload' do |
| 453 | + context = LaunchDarkly::LDContext.create({ key: 'user-key', kind: 'user' }) |
| 454 | + config = ai_client.completion_config(key: 'model-config-with-key-version', context:) |
| 455 | + |
| 456 | + expect(config.model).not_to be_nil |
| 457 | + expect(config.model.model_key).to eq('my-model') |
| 458 | + expect(config.model.model_version).to eq(2) |
| 459 | + end |
| 460 | + |
| 461 | + it 'stamps modelKey and modelVersion on track data' do |
| 462 | + context = LaunchDarkly::LDContext.create({ key: 'user-key', kind: 'user' }) |
| 463 | + config = ai_client.completion_config(key: 'model-config-with-key-version', context:) |
| 464 | + |
| 465 | + tracker = config.create_tracker |
| 466 | + expect(ld_client).to receive(:track).with( |
| 467 | + '$ld:ai:generation:success', |
| 468 | + context, |
| 469 | + hash_including(modelKey: 'my-model', modelVersion: 2), |
| 470 | + 1 |
| 471 | + ) |
| 472 | + tracker.track_success |
| 473 | + end |
| 474 | + |
| 475 | + it 'defaults modelVersion to 1 and omits modelKey when absent from payload' do |
| 476 | + context = LaunchDarkly::LDContext.create({ key: 'user-key', kind: 'user' }) |
| 477 | + config = ai_client.completion_config(key: 'model-config', context:, variables: { 'name' => 'World' }) |
| 478 | + |
| 479 | + tracker = config.create_tracker |
| 480 | + flag_data = tracker.send(:flag_data) |
| 481 | + |
| 482 | + expect(flag_data[:modelVersion]).to eq(1) |
| 483 | + expect(flag_data).not_to have_key(:modelKey) |
| 484 | + end |
| 485 | + |
| 486 | + it 'uses explicit modelVersion from payload when modelKey is absent' do |
| 487 | + td.update(td.flag('model-config-version-only') |
| 488 | + .variations( |
| 489 | + { |
| 490 | + model: { name: 'gpt-4', modelVersion: 3 }, |
| 491 | + provider: { name: 'openai' }, |
| 492 | + messages: [], |
| 493 | + _ldMeta: { enabled: true, variationKey: 'v1', version: 1 }, |
| 494 | + } |
| 495 | + ) |
| 496 | + .variation_for_all(0)) |
| 497 | + |
| 498 | + context = LaunchDarkly::LDContext.create({ key: 'user-key', kind: 'user' }) |
| 499 | + config = ai_client.completion_config(key: 'model-config-version-only', context:) |
| 500 | + |
| 501 | + tracker = config.create_tracker |
| 502 | + flag_data = tracker.send(:flag_data) |
| 503 | + |
| 504 | + expect(flag_data[:modelVersion]).to eq(3) |
| 505 | + expect(flag_data).not_to have_key(:modelKey) |
411 | 506 | end |
412 | 507 |
|
413 | 508 | it 'create_tracker returns a tracker even for disabled configs from evaluation' do |
|
434 | 529 | expect(restored.send(:flag_data)[:configKey]).to eq('model-config') |
435 | 530 | expect(restored.send(:flag_data)[:modelName]).to eq('') |
436 | 531 | expect(restored.send(:flag_data)[:providerName]).to eq('') |
| 532 | + expect(restored.send(:flag_data)[:modelVersion]).to eq(1) |
| 533 | + expect(restored.send(:flag_data)).not_to have_key(:modelKey) |
437 | 534 | end |
438 | 535 |
|
439 | 536 | it 'each tracker has independent at-most-once tracking' do |
|
0 commit comments