@bxb1337/windsurf-fast-context 1.0.9 → 1.1.1

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.
@@ -7,38 +7,6 @@ describe('convertResponse', () => {
7
7
  const result = convertResponse(Buffer.from('plain response text', 'utf8'));
8
8
  expect(result).toEqual([{ type: 'text', text: 'plain response text' }]);
9
9
  });
10
- it('tool-call - parses tool markers and preserves surrounding text', () => {
11
- const input = 'Before [TOOL_CALLS]searchDocs[ARGS]{"query":"prompt converter"} between [TOOL_CALLS]answer[ARGS]{"answer":"final answer"} after';
12
- const result = convertResponse(Buffer.from(input, 'utf8'));
13
- expect(result).toEqual([
14
- { type: 'text', text: 'Before ' },
15
- {
16
- type: 'tool-call',
17
- toolCallId: 'toolcall_1',
18
- toolName: 'searchDocs',
19
- input: { query: 'prompt converter' },
20
- },
21
- { type: 'text', text: ' between ' },
22
- {
23
- type: 'tool-call',
24
- toolCallId: 'toolcall_2',
25
- toolName: 'answer',
26
- input: { answer: 'final answer' },
27
- },
28
- { type: 'text', text: ' after' },
29
- ]);
30
- });
31
- it('malformed - invalid marker json remains text and does not throw', () => {
32
- const input = 'prefix [TOOL_CALLS]searchDocs[ARGS]{"query": nope} suffix';
33
- expect(() => convertResponse(Buffer.from(input, 'utf8'))).not.toThrow();
34
- const result = convertResponse(Buffer.from(input, 'utf8'));
35
- const combinedText = result
36
- .filter((part) => part.type === 'text')
37
- .map((part) => part.text)
38
- .join('');
39
- expect(result.every((part) => part.type === 'text')).toBe(true);
40
- expect(combinedText).toBe(input);
41
- });
42
10
  it('protobuf payload - extracts clean utf8 text without binary mojibake prefix', () => {
43
11
  const payload = new ProtobufEncoder();
44
12
  payload.writeVarint(1, 150);
@@ -46,20 +14,6 @@ describe('convertResponse', () => {
46
14
  const result = convertResponse(payload.toBuffer());
47
15
  expect(result).toEqual([{ type: 'text', text: '你好,TypeScript' }]);
48
16
  });
49
- it('protobuf payload - still parses tool-call markers from extracted strings', () => {
50
- const payload = new ProtobufEncoder();
51
- payload.writeVarint(1, 150);
52
- payload.writeString(2, '[TOOL_CALLS]answer[ARGS]{"answer":"final answer"}');
53
- const result = convertResponse(payload.toBuffer());
54
- expect(result).toEqual([
55
- {
56
- type: 'tool-call',
57
- toolCallId: 'toolcall_1',
58
- toolName: 'answer',
59
- input: { answer: 'final answer' },
60
- },
61
- ]);
62
- });
63
17
  it('protobuf payload - ignores metadata strings and keeps main text field', () => {
64
18
  const payload = new ProtobufEncoder();
65
19
  payload.writeString(1, 'meta');
@@ -77,70 +31,52 @@ describe('convertResponse', () => {
77
31
  const result = convertResponse(Buffer.from(input, 'utf8'));
78
32
  expect(result).toEqual([{ type: 'text', text: 'Hello world' }]);
79
33
  });
80
- it('parses OpenAI-style TOOL_CALLS with numeric IDs', () => {
81
- const input = 'TOOL_CALLS{"type":"function","function":{"name":3,"parameters":{"file_path":"/home/test","search_pattern":"binance"}}}{}';
34
+ // Strict OpenAI array format tests
35
+ it('parses strict OpenAI array with single tool call', () => {
36
+ const input = '[{"type":"function","function":{"name":"search","parameters":{"q":"test"}}}]';
82
37
  const result = convertResponse(Buffer.from(input, 'utf8'));
83
38
  expect(result).toEqual([
84
- {
85
- type: 'tool-call',
86
- toolCallId: 'toolcall_1',
87
- toolName: 'grep',
88
- input: { file_path: '/home/test', search_pattern: 'binance' },
89
- },
39
+ { type: 'tool-call', toolCallId: 'toolcall_1', toolName: 'search', input: { q: 'test' } }
90
40
  ]);
91
41
  });
92
- it('parses multiple OpenAI-style tool calls', () => {
93
- const input = 'TOOL_CALLS{"type":"function","function":{"name":1,"parameters":{"file_path":"/home/test"}}}, {"type":"function","function":{"name":2,"parameters":{"pattern":"*.ts"}}}{}';
42
+ it('parses strict OpenAI array with multiple tool calls', () => {
43
+ const input = '[{"type":"function","function":{"name":"read","parameters":{"path":"/a"}}},{"type":"function","function":{"name":"grep","parameters":{"pattern":"foo"}}}]';
94
44
  const result = convertResponse(Buffer.from(input, 'utf8'));
95
45
  expect(result).toEqual([
96
- {
97
- type: 'tool-call',
98
- toolCallId: 'toolcall_1',
99
- toolName: 'read',
100
- input: { file_path: '/home/test' },
101
- },
102
- {
103
- type: 'tool-call',
104
- toolCallId: 'toolcall_2',
105
- toolName: 'glob',
106
- input: { pattern: '*.ts' },
107
- },
46
+ { type: 'tool-call', toolCallId: 'toolcall_1', toolName: 'read', input: { path: '/a' } },
47
+ { type: 'tool-call', toolCallId: 'toolcall_2', toolName: 'grep', input: { pattern: 'foo' } }
108
48
  ]);
109
49
  });
110
- it('maps unknown tool IDs to tool_N format', () => {
111
- const input = 'TOOL_CALLS{"type":"function","function":{"name":99,"parameters":{"arg":"value"}}}{}';
50
+ it('parses strict OpenAI array with empty parameters', () => {
51
+ const input = '[{"type":"function","function":{"name":"list","parameters":{}}}]';
112
52
  const result = convertResponse(Buffer.from(input, 'utf8'));
113
53
  expect(result).toEqual([
114
- {
115
- type: 'tool-call',
116
- toolCallId: 'toolcall_1',
117
- toolName: 'tool_99',
118
- input: { arg: 'value' },
119
- },
54
+ { type: 'tool-call', toolCallId: 'toolcall_1', toolName: 'list', input: {} }
120
55
  ]);
121
56
  });
122
- it('handles OpenAI-style with string tool names', () => {
123
- const input = 'TOOL_CALLS{"type":"function","function":{"name":"custom_tool","parameters":{"key":"value"}}}{}';
57
+ it('returns text for old marker format (no backward compat)', () => {
58
+ const input = '[TOOL_CALLS]search[ARGS]{"q":"test"}';
124
59
  const result = convertResponse(Buffer.from(input, 'utf8'));
125
- expect(result).toEqual([
126
- {
127
- type: 'tool-call',
128
- toolCallId: 'toolcall_1',
129
- toolName: 'custom_tool',
130
- input: { key: 'value' },
131
- },
132
- ]);
60
+ expect(result).toEqual([{ type: 'text', text: '[TOOL_CALLS]search[ARGS]{"q":"test"}' }]);
133
61
  });
134
- it('handles OpenAI-style with string name "answer" - emits as tool-call', () => {
135
- const input = 'TOOL_CALLS{"type":"function","function":{"name":"answer","parameters":{"answer":"final answer"}}}{}';
62
+ it('returns text for old TOOL_CALLS format (no backward compat)', () => {
63
+ const input = 'TOOL_CALLS{"type":"function","function":{"name":3,"parameters":{"q":"test"}}}{}';
136
64
  const result = convertResponse(Buffer.from(input, 'utf8'));
137
- expect(result).toEqual([
138
- {
139
- type: 'tool-call',
140
- toolCallId: 'toolcall_1',
141
- toolName: 'answer',
142
- input: { answer: 'final answer' },
143
- },
144
- ]);
65
+ expect(result).toEqual([{ type: 'text', text: input }]);
66
+ });
67
+ it('returns text for non-array JSON', () => {
68
+ const input = '{"type":"function","function":{"name":"search","parameters":{}}}';
69
+ const result = convertResponse(Buffer.from(input, 'utf8'));
70
+ expect(result).toEqual([{ type: 'text', text: input }]);
71
+ });
72
+ it('returns text for empty array', () => {
73
+ const input = '[]';
74
+ const result = convertResponse(Buffer.from(input, 'utf8'));
75
+ expect(result).toEqual([{ type: 'text', text: '[]' }]);
76
+ });
77
+ it('returns text for malformed JSON array', () => {
78
+ const input = '[{"type":"function","function":{"name":"search","parameters":';
79
+ const result = convertResponse(Buffer.from(input, 'utf8'));
80
+ expect(result).toEqual([{ type: 'text', text: input }]);
145
81
  });
146
82
  });
@@ -17,8 +17,15 @@ const WS_APP_VER = process.env.WS_APP_VER ?? '1.48.2';
17
17
  const WS_LS_VER = process.env.WS_LS_VER ?? '1.9544.35';
18
18
  const SENTRY_PUBLIC_KEY = 'b813f73488da69eedec534dba1029111';
19
19
  const CONNECT_USER_AGENT = 'connect-go/1.18.1 (go1.25.5)';
20
+ const TOOL_FORMAT_INSTRUCTION = `When you need to call tools, you must format your response as a JSON array of tool calls following the OpenAI function calling format. Each tool call must be an object with "type" set to "function" and a "function" object containing "name" (string matching one of the provided tool names) and "parameters" (object with the tool's arguments). Output ONLY the JSON array, no surrounding text.
21
+
22
+ Example format:
23
+ [{"type": "function", "function": {"name": "tool_name", "parameters": {"arg1": "value1"}}}]
24
+
25
+ For multiple tool calls:
26
+ [{"type": "function", "function": {"name": "tool1", "parameters": {"arg1": "value1"}}}, {"type": "function", "function": {"name": "tool2", "parameters": {"arg2": "value2"}}}]`;
20
27
  export class DevstralLanguageModel {
21
- specificationVersion = 'v3';
28
+ specificationVersion = 'v2';
22
29
  provider = 'windsurf';
23
30
  modelId;
24
31
  supportedUrls = {};
@@ -55,16 +62,13 @@ export class DevstralLanguageModel {
55
62
  const responseFrame = await this.transport.postUnary(`${this.baseURL}${API_SERVICE_PATH}${DEVSTRAL_STREAM_PATH}`, requestFrame, headers);
56
63
  const { payloads: responsePayloads } = connectFrameDecode(responseFrame);
57
64
  const payloads = responsePayloads.length > 0 ? responsePayloads : [responseFrame];
58
- const content = payloads.flatMap((payload) => toV3Content(convertResponse(payload)));
65
+ const content = payloads.flatMap((payload) => toV2Content(convertResponse(payload)));
59
66
  const unified = content.some((part) => part.type === 'tool-call')
60
67
  ? 'tool-calls'
61
68
  : 'stop';
62
69
  return {
63
70
  content,
64
- finishReason: {
65
- unified,
66
- raw: undefined,
67
- },
71
+ finishReason: unified,
68
72
  usage: emptyUsage(),
69
73
  warnings: [],
70
74
  };
@@ -122,7 +126,7 @@ export class DevstralLanguageModel {
122
126
  break;
123
127
  }
124
128
  pending = frameResult.rest;
125
- const contentParts = toV3Content(convertResponse(frameResult.payload));
129
+ const contentParts = toV2Content(convertResponse(frameResult.payload));
126
130
  for (const part of contentParts) {
127
131
  if (isAborted(options.abortSignal)) {
128
132
  safeClose(controller);
@@ -172,10 +176,7 @@ export class DevstralLanguageModel {
172
176
  const unified = hasToolCalls ? 'tool-calls' : 'stop';
173
177
  safeEnqueue(controller, {
174
178
  type: 'finish',
175
- finishReason: {
176
- unified,
177
- raw: undefined,
178
- },
179
+ finishReason: unified,
179
180
  usage: emptyUsage(),
180
181
  });
181
182
  safeClose(controller);
@@ -189,10 +190,7 @@ export class DevstralLanguageModel {
189
190
  });
190
191
  safeEnqueue(controller, {
191
192
  type: 'finish',
192
- finishReason: {
193
- unified: 'error',
194
- raw: undefined,
195
- },
193
+ finishReason: 'error',
196
194
  usage: emptyUsage(),
197
195
  });
198
196
  }
@@ -251,20 +249,12 @@ function isAborted(signal) {
251
249
  }
252
250
  function emptyUsage() {
253
251
  return {
254
- inputTokens: {
255
- total: undefined,
256
- noCache: undefined,
257
- cacheRead: undefined,
258
- cacheWrite: undefined,
259
- },
260
- outputTokens: {
261
- total: undefined,
262
- text: undefined,
263
- reasoning: undefined,
264
- },
252
+ inputTokens: undefined,
253
+ outputTokens: undefined,
254
+ totalTokens: undefined,
265
255
  };
266
256
  }
267
- function toV3Content(parts) {
257
+ function toV2Content(parts) {
268
258
  return parts.map((part) => {
269
259
  if (part.type !== 'tool-call') {
270
260
  return part;
@@ -284,10 +274,13 @@ function isFunctionTool(tool) {
284
274
  function buildGenerateRequest(input) {
285
275
  const request = new ProtobufEncoder();
286
276
  request.writeMessage(1, buildMetadata(input.apiKey, input.jwt));
287
- for (const message of input.messages) {
277
+ const functionTools = input.tools?.filter(isFunctionTool) ?? [];
278
+ const messages = functionTools.length > 0
279
+ ? [{ role: 5, content: TOOL_FORMAT_INSTRUCTION }, ...input.messages]
280
+ : input.messages;
281
+ for (const message of messages) {
288
282
  request.writeMessage(2, buildMessage(message));
289
283
  }
290
- const functionTools = input.tools?.filter(isFunctionTool) ?? [];
291
284
  if (functionTools.length > 0) {
292
285
  const toolsArray = functionTools.map((tool) => ({
293
286
  type: 'function',
@@ -131,25 +131,17 @@ describe('DevstralLanguageModel doGenerate', () => {
131
131
  });
132
132
  };
133
133
  const model = new DevstralLanguageModel({ apiKey: 'test-api-key', fetch: fakeFetch, baseURL: 'https://windsurf.test' });
134
- expect(model.specificationVersion).toBe('v3');
134
+ expect(model.specificationVersion).toBe('v2');
135
135
  expect(model.supportedUrls).toEqual({});
136
136
  const result = await model.doGenerate({
137
137
  prompt: [{ role: 'user', content: [{ type: 'text', text: 'Find auth logic.' }] }],
138
138
  });
139
139
  expect(result.content).toEqual([{ type: 'text', text: 'generated answer' }]);
140
- expect(result.finishReason).toEqual({ unified: 'stop', raw: undefined });
140
+ expect(result.finishReason).toBe('stop');
141
141
  expect(result.usage).toEqual({
142
- inputTokens: {
143
- total: undefined,
144
- noCache: undefined,
145
- cacheRead: undefined,
146
- cacheWrite: undefined,
147
- },
148
- outputTokens: {
149
- total: undefined,
150
- text: undefined,
151
- reasoning: undefined,
152
- },
142
+ inputTokens: undefined,
143
+ outputTokens: undefined,
144
+ totalTokens: undefined,
153
145
  });
154
146
  expect(calls).toHaveLength(2);
155
147
  expect(calls[0]?.url).toBe('https://windsurf.test/exa.auth_pb.AuthService/GetUserJwt');
@@ -169,7 +161,7 @@ describe('DevstralLanguageModel doGenerate', () => {
169
161
  return new Response(Uint8Array.from(Buffer.from(jwt, 'utf8')), { status: 200 });
170
162
  }
171
163
  requestBodies.push(bufferFromBody(init?.body));
172
- const payload = Buffer.from('[TOOL_CALLS]searchRepo[ARGS]{"query":"jwt manager"}', 'utf8');
164
+ const payload = Buffer.from('[{"type":"function","function":{"name":"searchRepo","parameters":{"query":"jwt manager"}}}]', 'utf8');
173
165
  return new Response(Uint8Array.from(connectFrameEncode(payload)), { status: 200 });
174
166
  };
175
167
  const model = new DevstralLanguageModel({ apiKey: 'tools-key', fetch: fakeFetch, baseURL: 'https://windsurf.test' });
@@ -198,7 +190,7 @@ describe('DevstralLanguageModel doGenerate', () => {
198
190
  input: '{"query":"jwt manager"}',
199
191
  },
200
192
  ]);
201
- expect(result.finishReason).toEqual({ unified: 'tool-calls', raw: undefined });
193
+ expect(result.finishReason).toBe('tool-calls');
202
194
  const strings = extractStrings(decodeRequestPayload(requestBodies[0] ?? Buffer.alloc(0)));
203
195
  const toolsPayload = extractToolsPayload(strings);
204
196
  expect(toolsPayload).toBeDefined();
@@ -248,7 +240,7 @@ describe('DevstralLanguageModel doGenerate', () => {
248
240
  },
249
241
  },
250
242
  {
251
- type: 'provider',
243
+ type: 'provider-defined',
252
244
  id: 'windsurf.restricted_exec',
253
245
  name: 'restricted_exec',
254
246
  args: { mode: 'read-only' },
@@ -281,6 +273,83 @@ describe('DevstralLanguageModel doGenerate', () => {
281
273
  const strings = extractStrings(decodeRequestPayload(requestBodies[0] ?? Buffer.alloc(0)));
282
274
  expect(extractToolsPayload(strings)).toBeUndefined();
283
275
  });
276
+ it('injects tool format instruction into request when tools are present', async () => {
277
+ const requestBodies = [];
278
+ const jwt = makeJwt(4_200_000_100, 'instruction');
279
+ const fakeFetch = async (input, init) => {
280
+ const url = String(input);
281
+ if (url.endsWith('/GetUserJwt')) {
282
+ return new Response(Uint8Array.from(Buffer.from(jwt, 'utf8')), { status: 200 });
283
+ }
284
+ requestBodies.push(bufferFromBody(init?.body));
285
+ return new Response(Uint8Array.from(connectFrameEncode(Buffer.from('ok', 'utf8'))), { status: 200 });
286
+ };
287
+ const model = new DevstralLanguageModel({ apiKey: 'tools-key', fetch: fakeFetch, baseURL: 'https://windsurf.test' });
288
+ await model.doGenerate({
289
+ prompt: [{ role: 'user', content: [{ type: 'text', text: 'Search for auth.' }] }],
290
+ tools: [
291
+ {
292
+ type: 'function',
293
+ name: 'searchRepo',
294
+ description: 'Search repository files',
295
+ inputSchema: {
296
+ type: 'object',
297
+ properties: { query: { type: 'string' } },
298
+ required: ['query'],
299
+ },
300
+ },
301
+ ],
302
+ });
303
+ const strings = extractStrings(decodeRequestPayload(requestBodies[0] ?? Buffer.alloc(0)));
304
+ const combined = strings.join('\n');
305
+ expect(combined).toContain('When you need to call tools');
306
+ });
307
+ it('does not inject tool format instruction when no tools provided', async () => {
308
+ const requestBodies = [];
309
+ const jwt = makeJwt(4_200_000_101, 'no-instruction');
310
+ const fakeFetch = async (input, init) => {
311
+ const url = String(input);
312
+ if (url.endsWith('/GetUserJwt')) {
313
+ return new Response(Uint8Array.from(Buffer.from(jwt, 'utf8')), { status: 200 });
314
+ }
315
+ requestBodies.push(bufferFromBody(init?.body));
316
+ return new Response(Uint8Array.from(connectFrameEncode(Buffer.from('ok', 'utf8'))), { status: 200 });
317
+ };
318
+ const model = new DevstralLanguageModel({ apiKey: 'tools-key', fetch: fakeFetch, baseURL: 'https://windsurf.test' });
319
+ await model.doGenerate({
320
+ prompt: [{ role: 'user', content: [{ type: 'text', text: 'Find auth logic.' }] }],
321
+ });
322
+ const strings = extractStrings(decodeRequestPayload(requestBodies[0] ?? Buffer.alloc(0)));
323
+ const combined = strings.join('\n');
324
+ expect(combined).not.toContain('When you need to call tools');
325
+ });
326
+ it('does not inject tool format instruction when only provider-defined tools', async () => {
327
+ const requestBodies = [];
328
+ const jwt = makeJwt(4_200_000_102, 'provider-only');
329
+ const fakeFetch = async (input, init) => {
330
+ const url = String(input);
331
+ if (url.endsWith('/GetUserJwt')) {
332
+ return new Response(Uint8Array.from(Buffer.from(jwt, 'utf8')), { status: 200 });
333
+ }
334
+ requestBodies.push(bufferFromBody(init?.body));
335
+ return new Response(Uint8Array.from(connectFrameEncode(Buffer.from('ok', 'utf8'))), { status: 200 });
336
+ };
337
+ const model = new DevstralLanguageModel({ apiKey: 'tools-key', fetch: fakeFetch, baseURL: 'https://windsurf.test' });
338
+ await model.doGenerate({
339
+ prompt: [{ role: 'user', content: [{ type: 'text', text: 'Use provider tools.' }] }],
340
+ tools: [
341
+ {
342
+ type: 'provider-defined',
343
+ id: 'some-provider-tool',
344
+ name: 'providerTool',
345
+ args: {},
346
+ },
347
+ ],
348
+ });
349
+ const strings = extractStrings(decodeRequestPayload(requestBodies[0] ?? Buffer.alloc(0)));
350
+ const combined = strings.join('\n');
351
+ expect(combined).not.toContain('When you need to call tools');
352
+ });
284
353
  });
285
354
  describe('DevstralLanguageModel doStream', () => {
286
355
  it('stream-text resolves before full body arrives and emits parts incrementally', async () => {
@@ -368,22 +437,11 @@ describe('DevstralLanguageModel doStream', () => {
368
437
  expect(parts[4]).toMatchObject({ type: 'text-delta', delta: 'world' });
369
438
  expect(parts[6]).toEqual({
370
439
  type: 'finish',
371
- finishReason: {
372
- unified: 'stop',
373
- raw: undefined,
374
- },
440
+ finishReason: 'stop',
375
441
  usage: {
376
- inputTokens: {
377
- total: undefined,
378
- noCache: undefined,
379
- cacheRead: undefined,
380
- cacheWrite: undefined,
381
- },
382
- outputTokens: {
383
- total: undefined,
384
- text: undefined,
385
- reasoning: undefined,
386
- },
442
+ inputTokens: undefined,
443
+ outputTokens: undefined,
444
+ totalTokens: undefined,
387
445
  },
388
446
  });
389
447
  }
@@ -396,7 +454,7 @@ describe('DevstralLanguageModel doStream', () => {
396
454
  });
397
455
  it('stream-tool emits tool-input deltas before final tool-call and finish', async () => {
398
456
  const jwt = makeJwt(4_300_000_001, 'stream-tool');
399
- const toolPayload = Buffer.from('[TOOL_CALLS]searchRepo[ARGS]{"query":"jwt manager"}', 'utf8');
457
+ const toolPayload = Buffer.from('[{"type":"function","function":{"name":"searchRepo","parameters":{"query":"jwt manager"}}}]', 'utf8');
400
458
  const frames = Buffer.concat([connectFrameEncode(toolPayload)]);
401
459
  const fakeFetch = async (input) => {
402
460
  const url = String(input);
@@ -446,22 +504,11 @@ describe('DevstralLanguageModel doStream', () => {
446
504
  });
447
505
  expect(parts[6]).toEqual({
448
506
  type: 'finish',
449
- finishReason: {
450
- unified: 'tool-calls',
451
- raw: undefined,
452
- },
507
+ finishReason: 'tool-calls',
453
508
  usage: {
454
- inputTokens: {
455
- total: undefined,
456
- noCache: undefined,
457
- cacheRead: undefined,
458
- cacheWrite: undefined,
459
- },
460
- outputTokens: {
461
- total: undefined,
462
- text: undefined,
463
- reasoning: undefined,
464
- },
509
+ inputTokens: undefined,
510
+ outputTokens: undefined,
511
+ totalTokens: undefined,
465
512
  },
466
513
  });
467
514
  });
@@ -1,4 +1,4 @@
1
- import type { LanguageModelV3, LanguageModelV3CallOptions, LanguageModelV3GenerateResult, LanguageModelV3StreamResult } from '@ai-sdk/provider';
1
+ import type { LanguageModelV2, LanguageModelV2CallOptions } from '@ai-sdk/provider';
2
2
  import { JwtManager } from '../auth/jwt-manager.js';
3
3
  import { DevstralTransport } from '../transport/http.js';
4
4
  import type { WindsurfProviderOptions } from '../types/index.js';
@@ -7,8 +7,10 @@ export interface DevstralLanguageModelOptions extends WindsurfProviderOptions {
7
7
  transport?: DevstralTransport;
8
8
  jwtManager?: JwtManager;
9
9
  }
10
- export declare class DevstralLanguageModel implements LanguageModelV3 {
11
- readonly specificationVersion = "v3";
10
+ type LanguageModelV2GenerateResult = Awaited<ReturnType<LanguageModelV2['doGenerate']>>;
11
+ type LanguageModelV2StreamResult = Awaited<ReturnType<LanguageModelV2['doStream']>>;
12
+ export declare class DevstralLanguageModel implements LanguageModelV2 {
13
+ readonly specificationVersion = "v2";
12
14
  readonly provider = "windsurf";
13
15
  readonly modelId: string;
14
16
  readonly supportedUrls: Record<string, RegExp[]>;
@@ -18,6 +20,7 @@ export declare class DevstralLanguageModel implements LanguageModelV3 {
18
20
  private readonly transport;
19
21
  private readonly jwtManager;
20
22
  constructor(options?: DevstralLanguageModelOptions);
21
- doGenerate(options: LanguageModelV3CallOptions): Promise<LanguageModelV3GenerateResult>;
22
- doStream(options: LanguageModelV3CallOptions): Promise<LanguageModelV3StreamResult>;
23
+ doGenerate(options: LanguageModelV2CallOptions): Promise<LanguageModelV2GenerateResult>;
24
+ doStream(options: LanguageModelV2CallOptions): Promise<LanguageModelV2StreamResult>;
23
25
  }
26
+ export {};
@@ -6,7 +6,7 @@ export interface WindsurfProviderOptions {
6
6
  generateId?: () => string;
7
7
  }
8
8
  /**
9
- * Windsurf provider interface extending AI SDK V3 ProviderV3 pattern.
9
+ * Windsurf provider interface extending AI SDK V2 ProviderV2 pattern.
10
10
  * The provider is callable as a function and has a languageModel method.
11
11
  */
12
12
  export interface WindsurfProvider {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@bxb1337/windsurf-fast-context",
3
- "version": "1.0.9",
3
+ "version": "1.1.1",
4
4
  "description": "AI SDK V3 provider for Windsurf's Devstral code search API",
5
5
  "type": "module",
6
6
  "scripts": {