opencode-morphllm 0.0.6 → 0.0.8

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,69 +1,65 @@
1
1
  import { MorphClient } from '@morphllm/morphsdk';
2
- import {
3
- API_KEY,
4
- MORPH_MODEL_EASY,
5
- MORPH_MODEL_MEDIUM,
6
- MORPH_MODEL_HARD,
7
- MORPH_MODEL_DEFAULT,
8
- MORPH_ROUTER_ONLY_FIRST_MESSAGE,
9
- } from '../shared/config';
2
+ import { API_KEY, MORPH_MODEL_EASY, MORPH_MODEL_MEDIUM, MORPH_MODEL_HARD, MORPH_MODEL_DEFAULT, MORPH_ROUTER_PROMPT_CACHING_AWARE, MORPH_ROUTER_ENABLED, } from '../shared/config';
10
3
  // Lazy initialization to allow mocking in tests
11
4
  let morph = null;
12
5
  const sessionsWithModelSelected = new Set();
13
6
  function getMorphClient() {
14
- if (!morph) {
15
- morph = new MorphClient({ apiKey: API_KEY });
16
- }
17
- return morph;
7
+ if (!morph) {
8
+ morph = new MorphClient({ apiKey: API_KEY });
9
+ }
10
+ return morph;
18
11
  }
19
12
  function parseModel(s) {
20
- if (!s) return { providerID: '', modelID: '' };
21
- const [providerID = '', modelID = ''] = s.split('/');
22
- return { providerID, modelID };
13
+ if (!s)
14
+ return { providerID: '', modelID: '' };
15
+ const [providerID = '', modelID = ''] = s.split('/');
16
+ return { providerID, modelID };
23
17
  }
24
18
  function pickModelForDifficulty(difficulty) {
25
- const key = String(difficulty).toLowerCase();
26
- switch (key) {
27
- case 'easy':
28
- return parseModel(MORPH_MODEL_EASY);
29
- case 'medium':
30
- return parseModel(MORPH_MODEL_MEDIUM);
31
- case 'hard':
32
- return parseModel(MORPH_MODEL_HARD);
33
- default:
34
- return parseModel(MORPH_MODEL_DEFAULT);
35
- }
19
+ const key = String(difficulty).toLowerCase();
20
+ switch (key) {
21
+ case 'easy':
22
+ return parseModel(MORPH_MODEL_EASY);
23
+ case 'medium':
24
+ return parseModel(MORPH_MODEL_MEDIUM);
25
+ case 'hard':
26
+ return parseModel(MORPH_MODEL_HARD);
27
+ default:
28
+ return parseModel(MORPH_MODEL_DEFAULT);
29
+ }
36
30
  }
37
31
  export function createModelRouterHook() {
38
- return {
39
- 'chat.message': async (input, output) => {
40
- input.model = input.model ?? { providerID: '', modelID: '' };
41
- if (MORPH_ROUTER_ONLY_FIRST_MESSAGE) {
42
- if (sessionsWithModelSelected.has(input.sessionID)) {
43
- return;
44
- }
45
- }
46
- const promptText = extractPromptText(output.parts);
47
- const classifier =
48
- input.classify ??
49
- ((args) => getMorphClient().routers.raw.classify(args));
50
- const classification = await classifier({
51
- input: promptText,
52
- });
53
- const chosen = pickModelForDifficulty(classification?.difficulty);
54
- const finalProviderID = chosen.providerID || input.model.providerID;
55
- const finalModelID = chosen.modelID || input.model.modelID;
56
- input.model.providerID = finalProviderID;
57
- input.model.modelID = finalModelID;
58
- if (MORPH_ROUTER_ONLY_FIRST_MESSAGE) {
59
- sessionsWithModelSelected.add(input.sessionID);
60
- }
61
- },
62
- };
32
+ return {
33
+ 'chat.message': async (input, output) => {
34
+ if (!MORPH_ROUTER_ENABLED) {
35
+ return;
36
+ }
37
+ input.model = input.model ?? { providerID: '', modelID: '' };
38
+ if (MORPH_ROUTER_PROMPT_CACHING_AWARE) {
39
+ if (sessionsWithModelSelected.has(input.sessionID)) {
40
+ return;
41
+ }
42
+ }
43
+ const promptText = extractPromptText(output.parts);
44
+ const classifier = input.classify ??
45
+ ((args) => getMorphClient().routers.raw.classify(args));
46
+ const classification = await classifier({
47
+ input: promptText,
48
+ });
49
+ const chosen = pickModelForDifficulty(classification?.difficulty);
50
+ const finalProviderID = chosen.providerID || input.model.providerID;
51
+ const finalModelID = chosen.modelID || input.model.modelID;
52
+ input.model.providerID = finalProviderID;
53
+ input.model.modelID = finalModelID;
54
+ if (MORPH_ROUTER_ENABLED && MORPH_ROUTER_PROMPT_CACHING_AWARE) {
55
+ sessionsWithModelSelected.add(input.sessionID);
56
+ }
57
+ },
58
+ };
63
59
  }
64
60
  export function extractPromptText(parts) {
65
- return parts
66
- .filter((p) => p.type === 'text')
67
- .map((p) => p.text || '')
68
- .join(' ');
61
+ return parts
62
+ .filter((p) => p.type === 'text')
63
+ .map((p) => p.text || '')
64
+ .join(' ');
69
65
  }
@@ -1,240 +1,239 @@
1
1
  import { describe, it, expect, vi } from 'bun:test';
2
2
  vi.mock('@morphllm/morphsdk', () => ({
3
- MorphClient: vi.fn().mockImplementation(() => ({
4
- routers: {
5
- raw: {
6
- classify: vi.fn(),
7
- },
8
- },
9
- })),
3
+ MorphClient: vi.fn().mockImplementation(() => ({
4
+ routers: {
5
+ raw: {
6
+ classify: vi.fn(),
7
+ },
8
+ },
9
+ })),
10
10
  }));
11
11
  vi.mock('../shared/config', () => ({
12
- API_KEY: 'sk-test-api-key-123',
13
- MORPH_MODEL_EASY: 'easy/easy',
14
- MORPH_MODEL_MEDIUM: 'medium/medium',
15
- MORPH_MODEL_HARD: 'hard/hard',
16
- MORPH_MODEL_DEFAULT: 'default/default',
17
- MORPH_ROUTER_ONLY_FIRST_MESSAGE: false,
12
+ API_KEY: 'sk-test-api-key-123',
13
+ MORPH_MODEL_EASY: 'easy/easy',
14
+ MORPH_MODEL_MEDIUM: 'medium/medium',
15
+ MORPH_MODEL_HARD: 'hard/hard',
16
+ MORPH_MODEL_DEFAULT: 'default/default',
17
+ MORPH_ROUTER_PROMPT_CACHING_AWARE: false,
18
+ MORPH_ROUTER_ENABLED: true,
18
19
  }));
19
20
  import { createModelRouterHook, extractPromptText } from './router';
20
21
  describe('router.ts', () => {
21
- describe('extractPromptText', () => {
22
- it('should extract text from parts', () => {
23
- const parts = [
24
- { type: 'text', text: 'Hello' },
25
- { type: 'text', text: 'World' },
26
- ];
27
- expect(extractPromptText(parts)).toBe('Hello World');
22
+ describe('extractPromptText', () => {
23
+ it('should extract text from parts', () => {
24
+ const parts = [
25
+ { type: 'text', text: 'Hello' },
26
+ { type: 'text', text: 'World' },
27
+ ];
28
+ expect(extractPromptText(parts)).toBe('Hello World');
29
+ });
30
+ it('should handle empty parts', () => {
31
+ const parts = [];
32
+ expect(extractPromptText(parts)).toBe('');
33
+ });
34
+ it('should filter out non-text parts', () => {
35
+ const parts = [
36
+ { type: 'text', text: 'Hello' },
37
+ { type: 'other', text: 'Ignore' },
38
+ { type: 'text', text: 'World' },
39
+ ];
40
+ expect(extractPromptText(parts)).toBe('Hello World');
41
+ });
42
+ it('should handle parts with no text', () => {
43
+ const parts = [
44
+ { type: 'text', text: 'Hello' },
45
+ { type: 'text' },
46
+ { type: 'text', text: 'World' },
47
+ ];
48
+ expect(extractPromptText(parts)).toBe('Hello World');
49
+ });
50
+ it('should handle all non-text parts', () => {
51
+ const parts = [
52
+ { type: 'image', data: 'base64...' },
53
+ { type: 'tool_use', name: 'bash' },
54
+ ];
55
+ expect(extractPromptText(parts)).toBe('');
56
+ });
57
+ });
58
+ describe('createModelRouterHook', () => {
59
+ it('should return a chat.message hook', () => {
60
+ const hook = createModelRouterHook();
61
+ expect('chat.message' in hook).toBe(true);
62
+ expect(typeof hook['chat.message']).toBe('function');
63
+ });
64
+ it('should call the classifier with the correct input', async () => {
65
+ const hook = createModelRouterHook();
66
+ const classify = vi.fn().mockResolvedValue({ difficulty: 'easy' });
67
+ const input = {
68
+ sessionID: '123',
69
+ classify,
70
+ };
71
+ const output = {
72
+ message: {},
73
+ parts: [{ type: 'text', text: 'test prompt' }],
74
+ };
75
+ await hook['chat.message'](input, output);
76
+ expect(classify).toHaveBeenCalledWith({ input: 'test prompt' });
77
+ });
78
+ it('should assign the correct model based on difficulty', async () => {
79
+ const hook = createModelRouterHook();
80
+ const classify = vi.fn().mockResolvedValue({ difficulty: 'hard' });
81
+ const input = {
82
+ sessionID: '123',
83
+ classify,
84
+ };
85
+ const output = {
86
+ message: {},
87
+ parts: [{ type: 'text', text: 'test prompt' }],
88
+ };
89
+ await hook['chat.message'](input, output);
90
+ expect(input).toHaveProperty('model');
91
+ expect(input.model.providerID).toBe('hard');
92
+ expect(input.model.modelID).toBe('hard');
93
+ });
94
+ it('should use the default model if no difficulty is returned', async () => {
95
+ const hook = createModelRouterHook();
96
+ const classify = vi.fn().mockResolvedValue({});
97
+ const input = {
98
+ sessionID: '123',
99
+ classify,
100
+ };
101
+ const output = {
102
+ message: {},
103
+ parts: [{ type: 'text', text: 'test prompt' }],
104
+ };
105
+ await hook['chat.message'](input, output);
106
+ expect(input).toHaveProperty('model');
107
+ expect(input.model.providerID).toBe('default');
108
+ expect(input.model.modelID).toBe('default');
109
+ });
110
+ it('should use default model when router returns nothing', async () => {
111
+ const hook = createModelRouterHook();
112
+ const classify = vi.fn().mockResolvedValue({});
113
+ const input = {
114
+ sessionID: '123',
115
+ classify,
116
+ };
117
+ const output = {
118
+ message: {},
119
+ parts: [{ type: 'text', text: 'test prompt' }],
120
+ };
121
+ await hook['chat.message'](input, output);
122
+ expect(input).toHaveProperty('model');
123
+ expect(input.model.providerID).toBe('default');
124
+ expect(input.model.modelID).toBe('default');
125
+ });
126
+ it('should handle classifier throwing an error gracefully', async () => {
127
+ const hook = createModelRouterHook();
128
+ const classify = vi.fn().mockRejectedValue(new Error('API Error'));
129
+ const input = {
130
+ sessionID: '123',
131
+ classify,
132
+ };
133
+ const output = {
134
+ message: {},
135
+ parts: [{ type: 'text', text: 'test prompt' }],
136
+ };
137
+ await expect(hook['chat.message'](input, output)).rejects.toThrow('API Error');
138
+ });
139
+ it('should handle classifier returning null', async () => {
140
+ const hook = createModelRouterHook();
141
+ const classify = vi.fn().mockResolvedValue(null);
142
+ const input = {
143
+ sessionID: '123',
144
+ classify,
145
+ };
146
+ const output = {
147
+ message: {},
148
+ parts: [{ type: 'text', text: 'test prompt' }],
149
+ };
150
+ await hook['chat.message'](input, output);
151
+ expect(input.model.providerID).toBe('default');
152
+ expect(input.model.modelID).toBe('default');
153
+ });
154
+ it('should handle classifier returning undefined difficulty', async () => {
155
+ const hook = createModelRouterHook();
156
+ const classify = vi.fn().mockResolvedValue({ difficulty: undefined });
157
+ const input = {
158
+ sessionID: '123',
159
+ classify,
160
+ };
161
+ const output = {
162
+ message: {},
163
+ parts: [{ type: 'text', text: 'test prompt' }],
164
+ };
165
+ await hook['chat.message'](input, output);
166
+ expect(input.model.providerID).toBe('default');
167
+ expect(input.model.modelID).toBe('default');
168
+ });
169
+ it('should default to default model for invalid difficulty values', async () => {
170
+ const hook = createModelRouterHook();
171
+ const classify = vi.fn().mockResolvedValue({ difficulty: 'ultra-hard' });
172
+ const input = {
173
+ sessionID: '123',
174
+ classify,
175
+ };
176
+ const output = {
177
+ message: {},
178
+ parts: [{ type: 'text', text: 'test prompt' }],
179
+ };
180
+ await hook['chat.message'](input, output);
181
+ expect(input.model.providerID).toBe('default');
182
+ expect(input.model.modelID).toBe('default');
183
+ });
184
+ it('should default to default model for empty string difficulty', async () => {
185
+ const hook = createModelRouterHook();
186
+ const classify = vi.fn().mockResolvedValue({ difficulty: '' });
187
+ const input = {
188
+ sessionID: '123',
189
+ classify,
190
+ };
191
+ const output = {
192
+ message: {},
193
+ parts: [{ type: 'text', text: 'test prompt' }],
194
+ };
195
+ await hook['chat.message'](input, output);
196
+ expect(input.model.providerID).toBe('default');
197
+ expect(input.model.modelID).toBe('default');
198
+ });
199
+ it('should handle case-insensitive difficulty matching', async () => {
200
+ const hook = createModelRouterHook();
201
+ const classify = vi.fn().mockResolvedValue({ difficulty: 'HARD' });
202
+ const input = {
203
+ sessionID: '123',
204
+ classify,
205
+ };
206
+ const output = {
207
+ message: {},
208
+ parts: [{ type: 'text', text: 'test prompt' }],
209
+ };
210
+ await hook['chat.message'](input, output);
211
+ expect(input.model.providerID).toBe('hard');
212
+ expect(input.model.modelID).toBe('hard');
213
+ });
214
+ it('should route all messages when MORPH_ROUTER_PROMPT_CACHING_AWARE is disabled', async () => {
215
+ const hook = createModelRouterHook();
216
+ const classify = vi
217
+ .fn()
218
+ .mockResolvedValueOnce({ difficulty: 'hard' })
219
+ .mockResolvedValueOnce({ difficulty: 'easy' });
220
+ const sessionID = 'session-456';
221
+ const input1 = { sessionID, classify };
222
+ const output1 = {
223
+ message: {},
224
+ parts: [{ type: 'text', text: 'first message' }],
225
+ };
226
+ await hook['chat.message'](input1, output1);
227
+ expect(classify).toHaveBeenCalledTimes(1);
228
+ expect(input1.model.providerID).toBe('hard');
229
+ const input2 = { sessionID, classify };
230
+ const output2 = {
231
+ message: {},
232
+ parts: [{ type: 'text', text: 'second message' }],
233
+ };
234
+ await hook['chat.message'](input2, output2);
235
+ expect(classify).toHaveBeenCalledTimes(2);
236
+ expect(input2.model.providerID).toBe('easy');
237
+ });
28
238
  });
29
- it('should handle empty parts', () => {
30
- const parts = [];
31
- expect(extractPromptText(parts)).toBe('');
32
- });
33
- it('should filter out non-text parts', () => {
34
- const parts = [
35
- { type: 'text', text: 'Hello' },
36
- { type: 'other', text: 'Ignore' },
37
- { type: 'text', text: 'World' },
38
- ];
39
- expect(extractPromptText(parts)).toBe('Hello World');
40
- });
41
- it('should handle parts with no text', () => {
42
- const parts = [
43
- { type: 'text', text: 'Hello' },
44
- { type: 'text' },
45
- { type: 'text', text: 'World' },
46
- ];
47
- expect(extractPromptText(parts)).toBe('Hello World');
48
- });
49
- it('should handle all non-text parts', () => {
50
- const parts = [
51
- { type: 'image', data: 'base64...' },
52
- { type: 'tool_use', name: 'bash' },
53
- ];
54
- expect(extractPromptText(parts)).toBe('');
55
- });
56
- });
57
- describe('createModelRouterHook', () => {
58
- it('should return a chat.message hook', () => {
59
- const hook = createModelRouterHook();
60
- expect('chat.message' in hook).toBe(true);
61
- expect(typeof hook['chat.message']).toBe('function');
62
- });
63
- it('should call the classifier with the correct input', async () => {
64
- const hook = createModelRouterHook();
65
- const classify = vi.fn().mockResolvedValue({ difficulty: 'easy' });
66
- const input = {
67
- sessionID: '123',
68
- classify,
69
- };
70
- const output = {
71
- message: {},
72
- parts: [{ type: 'text', text: 'test prompt' }],
73
- };
74
- await hook['chat.message'](input, output);
75
- expect(classify).toHaveBeenCalledWith({ input: 'test prompt' });
76
- });
77
- it('should assign the correct model based on difficulty', async () => {
78
- const hook = createModelRouterHook();
79
- const classify = vi.fn().mockResolvedValue({ difficulty: 'hard' });
80
- const input = {
81
- sessionID: '123',
82
- classify,
83
- };
84
- const output = {
85
- message: {},
86
- parts: [{ type: 'text', text: 'test prompt' }],
87
- };
88
- await hook['chat.message'](input, output);
89
- expect(input).toHaveProperty('model');
90
- expect(input.model.providerID).toBe('hard');
91
- expect(input.model.modelID).toBe('hard');
92
- });
93
- it('should use the default model if no difficulty is returned', async () => {
94
- const hook = createModelRouterHook();
95
- const classify = vi.fn().mockResolvedValue({});
96
- const input = {
97
- sessionID: '123',
98
- classify,
99
- };
100
- const output = {
101
- message: {},
102
- parts: [{ type: 'text', text: 'test prompt' }],
103
- };
104
- await hook['chat.message'](input, output);
105
- expect(input).toHaveProperty('model');
106
- expect(input.model.providerID).toBe('default');
107
- expect(input.model.modelID).toBe('default');
108
- });
109
- it('should use default model when router returns nothing', async () => {
110
- const hook = createModelRouterHook();
111
- const classify = vi.fn().mockResolvedValue({});
112
- const input = {
113
- sessionID: '123',
114
- classify,
115
- };
116
- const output = {
117
- message: {},
118
- parts: [{ type: 'text', text: 'test prompt' }],
119
- };
120
- await hook['chat.message'](input, output);
121
- expect(input).toHaveProperty('model');
122
- expect(input.model.providerID).toBe('default');
123
- expect(input.model.modelID).toBe('default');
124
- });
125
- it('should handle classifier throwing an error gracefully', async () => {
126
- const hook = createModelRouterHook();
127
- const classify = vi.fn().mockRejectedValue(new Error('API Error'));
128
- const input = {
129
- sessionID: '123',
130
- classify,
131
- };
132
- const output = {
133
- message: {},
134
- parts: [{ type: 'text', text: 'test prompt' }],
135
- };
136
- await expect(hook['chat.message'](input, output)).rejects.toThrow(
137
- 'API Error'
138
- );
139
- });
140
- it('should handle classifier returning null', async () => {
141
- const hook = createModelRouterHook();
142
- const classify = vi.fn().mockResolvedValue(null);
143
- const input = {
144
- sessionID: '123',
145
- classify,
146
- };
147
- const output = {
148
- message: {},
149
- parts: [{ type: 'text', text: 'test prompt' }],
150
- };
151
- await hook['chat.message'](input, output);
152
- expect(input.model.providerID).toBe('default');
153
- expect(input.model.modelID).toBe('default');
154
- });
155
- it('should handle classifier returning undefined difficulty', async () => {
156
- const hook = createModelRouterHook();
157
- const classify = vi.fn().mockResolvedValue({ difficulty: undefined });
158
- const input = {
159
- sessionID: '123',
160
- classify,
161
- };
162
- const output = {
163
- message: {},
164
- parts: [{ type: 'text', text: 'test prompt' }],
165
- };
166
- await hook['chat.message'](input, output);
167
- expect(input.model.providerID).toBe('default');
168
- expect(input.model.modelID).toBe('default');
169
- });
170
- it('should default to default model for invalid difficulty values', async () => {
171
- const hook = createModelRouterHook();
172
- const classify = vi.fn().mockResolvedValue({ difficulty: 'ultra-hard' });
173
- const input = {
174
- sessionID: '123',
175
- classify,
176
- };
177
- const output = {
178
- message: {},
179
- parts: [{ type: 'text', text: 'test prompt' }],
180
- };
181
- await hook['chat.message'](input, output);
182
- expect(input.model.providerID).toBe('default');
183
- expect(input.model.modelID).toBe('default');
184
- });
185
- it('should default to default model for empty string difficulty', async () => {
186
- const hook = createModelRouterHook();
187
- const classify = vi.fn().mockResolvedValue({ difficulty: '' });
188
- const input = {
189
- sessionID: '123',
190
- classify,
191
- };
192
- const output = {
193
- message: {},
194
- parts: [{ type: 'text', text: 'test prompt' }],
195
- };
196
- await hook['chat.message'](input, output);
197
- expect(input.model.providerID).toBe('default');
198
- expect(input.model.modelID).toBe('default');
199
- });
200
- it('should handle case-insensitive difficulty matching', async () => {
201
- const hook = createModelRouterHook();
202
- const classify = vi.fn().mockResolvedValue({ difficulty: 'HARD' });
203
- const input = {
204
- sessionID: '123',
205
- classify,
206
- };
207
- const output = {
208
- message: {},
209
- parts: [{ type: 'text', text: 'test prompt' }],
210
- };
211
- await hook['chat.message'](input, output);
212
- expect(input.model.providerID).toBe('hard');
213
- expect(input.model.modelID).toBe('hard');
214
- });
215
- it('should route all messages when MORPH_ROUTER_ONLY_FIRST_MESSAGE is disabled', async () => {
216
- const hook = createModelRouterHook();
217
- const classify = vi
218
- .fn()
219
- .mockResolvedValueOnce({ difficulty: 'hard' })
220
- .mockResolvedValueOnce({ difficulty: 'easy' });
221
- const sessionID = 'session-456';
222
- const input1 = { sessionID, classify };
223
- const output1 = {
224
- message: {},
225
- parts: [{ type: 'text', text: 'first message' }],
226
- };
227
- await hook['chat.message'](input1, output1);
228
- expect(classify).toHaveBeenCalledTimes(1);
229
- expect(input1.model.providerID).toBe('hard');
230
- const input2 = { sessionID, classify };
231
- const output2 = {
232
- message: {},
233
- parts: [{ type: 'text', text: 'second message' }],
234
- };
235
- await hook['chat.message'](input2, output2);
236
- expect(classify).toHaveBeenCalledTimes(2);
237
- expect(input2.model.providerID).toBe('easy');
238
- });
239
- });
240
239
  });
@@ -1,31 +1,29 @@
1
1
  export declare function getMorphPluginConfigPath(): string;
2
2
  interface MorphRouterConfigs {
3
- MORPH_ROUTER_ENABLED?: boolean;
4
- MORPH_ROUTER_ONLY_FIRST_MESSAGE?: boolean;
5
- MORPH_MODEL_EASY?: string;
6
- MORPH_MODEL_MEDIUM?: string;
7
- MORPH_MODEL_HARD?: string;
8
- MORPH_MODEL_DEFAULT?: string;
3
+ MORPH_ROUTER_ENABLED?: boolean;
4
+ MORPH_ROUTER_PROMPT_CACHING_AWARE?: boolean;
5
+ MORPH_MODEL_EASY?: string;
6
+ MORPH_MODEL_MEDIUM?: string;
7
+ MORPH_MODEL_HARD?: string;
8
+ MORPH_MODEL_DEFAULT?: string;
9
9
  }
10
10
  interface MorphConfig {
11
- MORPH_API_KEY?: string;
12
- MORPH_ROUTER_CONFIGS?: MorphRouterConfigs;
13
- MORPH_ROUTER_ENABLED?: boolean;
14
- MORPH_ROUTER_ONLY_FIRST_MESSAGE?: boolean;
15
- MORPH_MODEL_EASY?: string;
16
- MORPH_MODEL_MEDIUM?: string;
17
- MORPH_MODEL_HARD?: string;
18
- MORPH_MODEL_DEFAULT?: string;
11
+ MORPH_API_KEY?: string;
12
+ MORPH_ROUTER_CONFIGS?: MorphRouterConfigs;
13
+ MORPH_ROUTER_ENABLED?: boolean;
14
+ MORPH_ROUTER_PROMPT_CACHING_AWARE?: boolean;
15
+ MORPH_MODEL_EASY?: string;
16
+ MORPH_MODEL_MEDIUM?: string;
17
+ MORPH_MODEL_HARD?: string;
18
+ MORPH_MODEL_DEFAULT?: string;
19
19
  }
20
20
  export declare function loadMorphPluginConfig(): MorphConfig | null;
21
- export declare function loadMorphPluginConfigWithProjectOverride(
22
- projectDir?: string
23
- ): MorphConfig;
21
+ export declare function loadMorphPluginConfigWithProjectOverride(projectDir?: string): MorphConfig;
24
22
  export declare const API_KEY: string;
25
23
  export declare const MORPH_MODEL_EASY: string;
26
24
  export declare const MORPH_MODEL_MEDIUM: string;
27
25
  export declare const MORPH_MODEL_HARD: string;
28
26
  export declare const MORPH_MODEL_DEFAULT: string;
29
27
  export declare const MORPH_ROUTER_ENABLED: boolean;
30
- export declare const MORPH_ROUTER_ONLY_FIRST_MESSAGE: boolean;
28
+ export declare const MORPH_ROUTER_PROMPT_CACHING_AWARE: boolean;
31
29
  export {};