forked from CopilotC-Nvim/CopilotChat.nvim
-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathmodels_spec.lua
More file actions
161 lines (139 loc) · 5.09 KB
/
Copy pathmodels_spec.lua
File metadata and controls
161 lines (139 loc) · 5.09 KB
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
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
describe('CopilotChat copilot provider models', function()
local curl = require('CopilotChat.utils.curl')
local providers = require('CopilotChat.config.providers')
local original_get = curl.get
local original_post = curl.post
before_each(function()
curl.get = function()
return { body = { data = {} } }
end
curl.post = function()
return { body = {} }
end
end)
after_each(function()
curl.get = original_get
curl.post = original_post
end)
local function model(id, picker, supported_endpoints)
return {
id = id,
name = id,
version = '1',
model_picker_enabled = picker,
capabilities = {
type = 'chat',
tokenizer = 'o200k_base',
limits = { max_prompt_tokens = 1000, max_output_tokens = 100 },
supports = { streaming = true, tool_calls = true },
},
supported_endpoints = supported_endpoints,
}
end
it('includes picker-disabled chat models with full metadata and auto', function()
curl.get = function()
return {
body = {
data = {
model('gpt-5.4-mini', false, { '/chat/completions' }),
model('gpt-5.4-responses', false, { '/responses' }),
{ id = 'embedding', capabilities = { type = 'embeddings' } },
},
},
}
end
local models = providers.copilot.get_models({})
local by_id = {}
for _, item in ipairs(models) do
by_id[item.id] = item
end
assert.is_false(by_id['gpt-5.4-mini'].picker)
assert.is_false(by_id['gpt-5.4-mini'].use_responses)
assert.equals('o200k_base', by_id['gpt-5.4-mini'].tokenizer)
assert.is_true(by_id['gpt-5.4-responses'].use_responses)
assert.is_nil(by_id.embedding)
assert.is_not_nil(by_id.auto)
end)
it('includes both picker-enabled and picker-disabled chat models', function()
curl.get = function()
return {
body = {
data = {
model('gpt-5.4-mini', true, { '/responses' }),
model('gpt-5.4-restricted', false, { '/chat/completions' }),
},
},
}
end
local models = providers.copilot.get_models({})
local by_id = {}
for _, item in ipairs(models) do
by_id[item.id] = item
end
assert.is_true(by_id['gpt-5.4-mini'].picker)
assert.is_true(by_id['gpt-5.4-mini'].use_responses)
assert.is_false(by_id['gpt-5.4-restricted'].picker)
assert.is_false(by_id['gpt-5.4-restricted'].use_responses)
end)
it('returns the selected model and session token for auto', function()
curl.post = function()
return { body = { selected_model = 'gpt-5.4-mini', session_token = 'session-token' } }
end
local selected, headers = providers.copilot.resolve_model({}, 'auto')
assert.equals('gpt-5.4-mini', selected)
assert.same({ ['Copilot-Session-Token'] = 'session-token' }, headers)
end)
it('returns non-auto models unchanged without headers', function()
local selected, headers = providers.copilot.resolve_model({}, 'gpt-5.4-mini')
assert.equals('gpt-5.4-mini', selected)
assert.is_nil(headers)
end)
it('provides auto fallback when all models are picker-disabled', function()
-- Restricted accounts have model_picker_enabled=false for every model.
-- The default config model (e.g. gpt-5-mini) is found in the cache but
-- cannot be called directly; the client must fall back to auto mode,
-- which resolves via /models/session and returns a session token.
curl.get = function()
return {
body = {
data = {
model('gpt-5-mini', false, { '/chat/completions' }),
},
},
}
end
curl.post = function()
return { body = { selected_model = 'gpt-5-mini', session_token = 'restricted-session-token' } }
end
local models = providers.copilot.get_models({})
local by_id = {}
for _, item in ipairs(models) do
by_id[item.id] = item
end
-- Every chat model is picker-disabled, but auto is still available
assert.is_false(by_id['gpt-5-mini'].picker)
assert.is_not_nil(by_id.auto)
-- Auto resolution returns a session token that authorizes the request
local selected, headers = providers.copilot.resolve_model({}, 'auto')
assert.equals('gpt-5-mini', selected)
assert.same({ ['Copilot-Session-Token'] = 'restricted-session-token' }, headers)
end)
it('returns a descriptive error when auto session endpoint fails', function()
-- The real async curl.post returns (response, err); the mock must match.
curl.post = function()
return { status = 403, body = '{"error":"forbidden"}' }, '{"error":"forbidden"}'
end
local ok, err = pcall(providers.copilot.resolve_model, {}, 'auto')
assert.is_false(ok)
assert.truthy(string.find(err, '403'))
assert.truthy(string.find(err, 'forbidden'))
end)
it('returns a descriptive error when auto returns no selected_model', function()
curl.post = function()
return { body = {} }
end
local ok, err = pcall(providers.copilot.resolve_model, {}, 'auto')
assert.is_false(ok)
assert.truthy(string.find(err, 'no selected_model'))
end)
end)