File size: 4,435 Bytes
dcedb25
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
import { describe, expect, it } from 'vitest';
import { parseKeysFromFile, parseModelList } from '../../lib/key-parser.js';

// #382: a paste can declare the models a custom endpoint serves next to its
// key, either as CUSTOM_<n>_MODELS beside the paired CUSTOM_<n>_* lines or as
// <PREFIX>_CUSTOM_MODELS beside <PREFIX>_BASE_URL + <PREFIX>_API_KEY/_KEY.

describe('parseModelList (#382)', () => {
  it('splits on commas and strips trailing capability suffixes', () => {
    expect(parseModelList('llama3, qwen3-TOOLS,pixtral-VISION')).toEqual([
      { id: 'llama3' },
      { id: 'qwen3', supportsTools: true },
      { id: 'pixtral', supportsVision: true },
    ]);
  });

  it('accepts both suffixes in either order', () => {
    expect(parseModelList('m1-TOOLS-VISION,m2-VISION-TOOLS')).toEqual([
      { id: 'm1', supportsTools: true, supportsVision: true },
      { id: 'm2', supportsTools: true, supportsVision: true },
    ]);
  });

  it('never touches a TOOLS/VISION that is not trailing', () => {
    expect(parseModelList('qwen-TOOLS-preview,llama-VISION-8b')).toEqual([
      { id: 'qwen-TOOLS-preview' },
      { id: 'llama-VISION-8b' },
    ]);
  });

  it('treats lowercase suffixes as part of the model id', () => {
    expect(parseModelList('devstral-tools,moondream-vision')).toEqual([
      { id: 'devstral-tools' },
      { id: 'moondream-vision' },
    ]);
  });

  it('drops blanks and dedupes ids after stripping', () => {
    expect(parseModelList('a, ,a-TOOLS,')).toEqual([{ id: 'a' }]);
  });
});

describe('model lists in .env pastes (#382)', () => {
  it('attaches CUSTOM_<n>_MODELS to its own endpoint only', () => {
    const env = [
      'CUSTOM_1_BASE_URL=http://relay-a.example/v1',
      'CUSTOM_1_KEY=sk-a',
      'CUSTOM_1_MODELS=llama3,qwen3-TOOLS',
      'CUSTOM_2_BASE_URL=http://relay-b.example/v1',
      'CUSTOM_2_KEY=sk-b',
    ].join('\n');
    const result = parseKeysFromFile(env, 'keys.env');
    expect(result.keys).toEqual([
      {
        rawKey: 'CUSTOM_1_KEY=sk-a',
        prefix: 'CUSTOM_',
        platform: 'custom',
        baseUrl: 'http://relay-a.example/v1',
        models: [{ id: 'llama3' }, { id: 'qwen3', supportsTools: true }],
      },
      {
        rawKey: 'CUSTOM_2_KEY=sk-b',
        prefix: 'CUSTOM_',
        platform: 'custom',
        baseUrl: 'http://relay-b.example/v1',
      },
    ]);
    expect(result.skipped).toEqual([]);
  });

  it('folds <PREFIX>_BASE_URL + <PREFIX>_API_KEY + <PREFIX>_CUSTOM_MODELS into a custom endpoint', () => {
    const env = [
      'MYRELAY_BASE_URL=http://myrelay.example/v1',
      'MYRELAY_API_KEY=sk-relay',
      'MYRELAY_CUSTOM_MODELS=deepseek-v3,text-embedding-qwen',
    ].join('\n');
    const result = parseKeysFromFile(env, 'keys.env');
    expect(result.keys).toEqual([
      expect.objectContaining({
        rawKey: 'MYRELAY_API_KEY=sk-relay',
        platform: 'custom',
        baseUrl: 'http://myrelay.example/v1',
        models: [{ id: 'deepseek-v3' }, { id: 'text-embedding-qwen' }],
      }),
    ]);
    expect(result.skipped).toEqual([]);
  });

  it('accepts <PREFIX>_KEY as the key spelling', () => {
    const env = [
      'MYRELAY_BASE_URL=http://myrelay.example/v1',
      'MYRELAY_KEY=sk-relay',
      'MYRELAY_CUSTOM_MODELS=deepseek-v3',
    ].join('\n');
    const result = parseKeysFromFile(env, 'keys.env');
    expect(result.keys).toEqual([
      expect.objectContaining({
        platform: 'custom',
        baseUrl: 'http://myrelay.example/v1',
        models: [{ id: 'deepseek-v3' }],
      }),
    ]);
  });

  it('leaves a <PREFIX>_BASE_URL pair alone when no models line makes it endpoint-defining', () => {
    const env = [
      'MYRELAY_BASE_URL=http://myrelay.example/v1',
      'MYRELAY_API_KEY=sk-relay',
    ].join('\n');
    const result = parseKeysFromFile(env, 'keys.env');
    expect(result.keys.every(k => k.platform !== 'custom')).toBe(true);
  });

  it('consumes and reports a models line with nothing to attach to', () => {
    const env = [
      'CUSTOM_1_MODELS=llama3',
      'ORPHAN_CUSTOM_MODELS=qwen',
    ].join('\n');
    const result = parseKeysFromFile(env, 'keys.env');
    // The list values must never fall through and be mistaken for key material.
    expect(result.keys).toEqual([]);
    expect(result.skipped).toEqual([
      expect.stringContaining('CUSTOM_1_MODELS'),
      expect.stringContaining('ORPHAN_CUSTOM_MODELS'),
    ]);
  });
});