@bxb1337/windsurf-fast-context 1.0.0

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.
Files changed (70) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +337 -0
  3. package/dist/auth/api-key.d.ts +2 -0
  4. package/dist/auth/api-key.test.d.ts +1 -0
  5. package/dist/auth/jwt-manager.d.ts +18 -0
  6. package/dist/auth/jwt-manager.test.d.ts +1 -0
  7. package/dist/cjs/auth/api-key.js +10 -0
  8. package/dist/cjs/auth/api-key.test.js +29 -0
  9. package/dist/cjs/auth/jwt-manager.js +94 -0
  10. package/dist/cjs/auth/jwt-manager.test.js +99 -0
  11. package/dist/cjs/conversion/prompt-converter.js +57 -0
  12. package/dist/cjs/conversion/prompt-converter.test.js +95 -0
  13. package/dist/cjs/conversion/response-converter.js +233 -0
  14. package/dist/cjs/conversion/response-converter.test.js +65 -0
  15. package/dist/cjs/index.js +23 -0
  16. package/dist/cjs/model/devstral-language-model.js +399 -0
  17. package/dist/cjs/model/devstral-language-model.test.js +410 -0
  18. package/dist/cjs/package.json +3 -0
  19. package/dist/cjs/protocol/connect-frame.js +40 -0
  20. package/dist/cjs/protocol/connect-frame.test.js +36 -0
  21. package/dist/cjs/protocol/protobuf.js +114 -0
  22. package/dist/cjs/protocol/protobuf.test.js +58 -0
  23. package/dist/cjs/provider.js +13 -0
  24. package/dist/cjs/provider.test.js +61 -0
  25. package/dist/cjs/transport/http.js +83 -0
  26. package/dist/cjs/transport/http.test.js +196 -0
  27. package/dist/cjs/types/index.js +2 -0
  28. package/dist/conversion/prompt-converter.d.ts +49 -0
  29. package/dist/conversion/prompt-converter.test.d.ts +1 -0
  30. package/dist/conversion/response-converter.d.ts +12 -0
  31. package/dist/conversion/response-converter.test.d.ts +1 -0
  32. package/dist/esm/auth/api-key.js +7 -0
  33. package/dist/esm/auth/api-key.test.js +27 -0
  34. package/dist/esm/auth/jwt-manager.js +90 -0
  35. package/dist/esm/auth/jwt-manager.test.js +97 -0
  36. package/dist/esm/conversion/prompt-converter.js +54 -0
  37. package/dist/esm/conversion/prompt-converter.test.js +93 -0
  38. package/dist/esm/conversion/response-converter.js +230 -0
  39. package/dist/esm/conversion/response-converter.test.js +63 -0
  40. package/dist/esm/dist/cjs/index.js +3 -0
  41. package/dist/esm/index.js +3 -0
  42. package/dist/esm/model/devstral-language-model.js +395 -0
  43. package/dist/esm/model/devstral-language-model.test.js +408 -0
  44. package/dist/esm/protocol/connect-frame.js +36 -0
  45. package/dist/esm/protocol/connect-frame.test.js +34 -0
  46. package/dist/esm/protocol/protobuf.js +108 -0
  47. package/dist/esm/protocol/protobuf.test.js +56 -0
  48. package/dist/esm/provider.js +9 -0
  49. package/dist/esm/provider.test.js +59 -0
  50. package/dist/esm/scripts/postbuild.js +10 -0
  51. package/dist/esm/src/index.js +1 -0
  52. package/dist/esm/transport/http.js +78 -0
  53. package/dist/esm/transport/http.test.js +194 -0
  54. package/dist/esm/types/index.js +1 -0
  55. package/dist/esm/vitest.config.js +6 -0
  56. package/dist/index.cjs +2 -0
  57. package/dist/index.d.ts +3 -0
  58. package/dist/index.js +1 -0
  59. package/dist/model/devstral-language-model.d.ts +118 -0
  60. package/dist/model/devstral-language-model.test.d.ts +1 -0
  61. package/dist/protocol/connect-frame.d.ts +10 -0
  62. package/dist/protocol/connect-frame.test.d.ts +1 -0
  63. package/dist/protocol/protobuf.d.ts +11 -0
  64. package/dist/protocol/protobuf.test.d.ts +1 -0
  65. package/dist/provider.d.ts +5 -0
  66. package/dist/provider.test.d.ts +1 -0
  67. package/dist/transport/http.d.ts +22 -0
  68. package/dist/transport/http.test.d.ts +1 -0
  69. package/dist/types/index.d.ts +37 -0
  70. package/package.json +51 -0
@@ -0,0 +1,59 @@
1
+ import { describe, it, expect } from 'vitest';
2
+ import { createWindsurfProvider, windsurf } from './provider.js';
3
+ import { DevstralLanguageModel } from './model/devstral-language-model.js';
4
+ // Helper to narrow the returned model in tests without using `any`.
5
+ function providerShape(m) {
6
+ return m;
7
+ }
8
+ describe('provider factory', () => {
9
+ it('with-api-key: constructs model when apiKey passed explicitly', () => {
10
+ const factory = createWindsurfProvider({ apiKey: 'explicit-key' });
11
+ const model = factory('MODEL_SWE_1_6_FAST');
12
+ expect(model).toBeInstanceOf(DevstralLanguageModel);
13
+ expect(providerShape(model).apiKey).toBe('explicit-key');
14
+ });
15
+ it('env-var: uses WINDSURF_API_KEY when apiKey not provided', () => {
16
+ const old = process.env.WINDSURF_API_KEY;
17
+ try {
18
+ process.env.WINDSURF_API_KEY = 'env-key';
19
+ const factory = createWindsurfProvider();
20
+ const model = factory('MODEL_SWE_1_6_FAST');
21
+ expect(providerShape(model).apiKey).toBe('env-key');
22
+ }
23
+ finally {
24
+ if (old === undefined)
25
+ delete process.env.WINDSURF_API_KEY;
26
+ else
27
+ process.env.WINDSURF_API_KEY = old;
28
+ }
29
+ });
30
+ it('no-key: throws when no api key available', () => {
31
+ const old = process.env.WINDSURF_API_KEY;
32
+ try {
33
+ delete process.env.WINDSURF_API_KEY;
34
+ const factory = createWindsurfProvider();
35
+ expect(() => factory('MODEL_SWE_1_6_FAST')).toThrow('WINDSURF_API_KEY is required');
36
+ }
37
+ finally {
38
+ if (old === undefined)
39
+ delete process.env.WINDSURF_API_KEY;
40
+ else
41
+ process.env.WINDSURF_API_KEY = old;
42
+ }
43
+ });
44
+ it('custom-baseurl: passes baseURL and trims trailing slash', () => {
45
+ const factory = createWindsurfProvider({ apiKey: 'k', baseURL: 'https://example.com/' });
46
+ const model = factory('MODEL_SWE_1_6_FAST');
47
+ expect(providerShape(model).baseURL).toBe('https://example.com');
48
+ });
49
+ it('custom-headers: passes headers through to model', () => {
50
+ const headers = { 'x-foo': 'bar' };
51
+ const factory = createWindsurfProvider({ apiKey: 'k', headers });
52
+ const model = factory('MODEL_SWE_1_6_FAST');
53
+ expect(providerShape(model).headers['x-foo']).toBe('bar');
54
+ });
55
+ it('exports: named factory and default windsurf', () => {
56
+ expect(typeof createWindsurfProvider).toBe('function');
57
+ expect(windsurf).toBeDefined();
58
+ });
59
+ });
@@ -0,0 +1,10 @@
1
+ import { writeFileSync, existsSync } from 'fs';
2
+ const esmIndex = `export * from './esm/index.js';\n`;
3
+ writeFileSync('dist/index.js', esmIndex);
4
+ const cjsIndex = `exports.__esModule = true;\nmodule.exports = require('./cjs/index.js');\n`;
5
+ writeFileSync('dist/index.cjs', cjsIndex);
6
+ const typesPath = 'dist/index.d.ts';
7
+ if (!existsSync(typesPath)) {
8
+ writeFileSync(typesPath, 'export {}\n');
9
+ }
10
+ console.log('postbuild: wrapped ESM/CJS entries and ensured types');
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,78 @@
1
+ export class DevstralTransportError extends Error {
2
+ code;
3
+ status;
4
+ constructor(code, message, status, options) {
5
+ super(message, options);
6
+ this.name = 'DevstralTransportError';
7
+ this.code = code;
8
+ this.status = status;
9
+ }
10
+ }
11
+ export class DevstralTransport {
12
+ fetchFn;
13
+ maxAttempts;
14
+ constructor(options = {}) {
15
+ this.fetchFn = options.fetch ?? fetch;
16
+ this.maxAttempts = Math.max(1, options.maxAttempts ?? 3);
17
+ }
18
+ postUnary(url, body, headers) {
19
+ return this.postUnaryRequest(url, body, headers);
20
+ }
21
+ postStreaming(url, body, headers, signal) {
22
+ return this.postStreamingRequest(url, body, headers, signal);
23
+ }
24
+ async postUnaryRequest(url, body, headers) {
25
+ const response = await this.post(url, body, headers);
26
+ return Buffer.from(await response.arrayBuffer());
27
+ }
28
+ async postStreamingRequest(url, body, headers, signal) {
29
+ const response = await this.post(url, body, headers, signal);
30
+ if (response.body == null) {
31
+ throw new DevstralTransportError('NETWORK_ERROR', 'Streaming response body is unavailable', response.status);
32
+ }
33
+ return response.body;
34
+ }
35
+ async post(url, body, headers, signal) {
36
+ for (let attempt = 1; attempt <= this.maxAttempts; attempt += 1) {
37
+ try {
38
+ const response = await this.fetchFn(url, {
39
+ method: 'POST',
40
+ headers,
41
+ body,
42
+ signal,
43
+ });
44
+ if (response.ok) {
45
+ return response;
46
+ }
47
+ if (response.status === 403) {
48
+ throw new DevstralTransportError('AUTH_ERROR', 'HTTP 403', response.status);
49
+ }
50
+ if (response.status === 429) {
51
+ throw new DevstralTransportError('RATE_LIMITED', 'HTTP 429', response.status);
52
+ }
53
+ if (response.status >= 500 && response.status < 600) {
54
+ if (attempt < this.maxAttempts) {
55
+ continue;
56
+ }
57
+ throw new DevstralTransportError('NETWORK_ERROR', `HTTP ${response.status}`, response.status);
58
+ }
59
+ throw new DevstralTransportError('NETWORK_ERROR', `HTTP ${response.status}`, response.status);
60
+ }
61
+ catch (error) {
62
+ if (isAbortError(error)) {
63
+ throw error;
64
+ }
65
+ if (error instanceof DevstralTransportError) {
66
+ throw error;
67
+ }
68
+ throw new DevstralTransportError('NETWORK_ERROR', 'Network request failed', undefined, {
69
+ cause: error,
70
+ });
71
+ }
72
+ }
73
+ throw new DevstralTransportError('NETWORK_ERROR', 'Network request failed');
74
+ }
75
+ }
76
+ function isAbortError(error) {
77
+ return error instanceof Error && error.name === 'AbortError';
78
+ }
@@ -0,0 +1,194 @@
1
+ import { describe, expect, it } from 'vitest';
2
+ import { DevstralTransport, DevstralTransportError } from './http.js';
3
+ const requestBytes = Buffer.from([1, 2, 3, 4]);
4
+ const responseBytes = Buffer.from([9, 8, 7, 6]);
5
+ function bufferFromBody(body) {
6
+ if (body == null) {
7
+ return Buffer.alloc(0);
8
+ }
9
+ if (typeof body === 'string') {
10
+ return Buffer.from(body, 'utf8');
11
+ }
12
+ if (body instanceof ArrayBuffer) {
13
+ return Buffer.from(body);
14
+ }
15
+ if (ArrayBuffer.isView(body)) {
16
+ return Buffer.from(body.buffer, body.byteOffset, body.byteLength);
17
+ }
18
+ throw new Error(`Unsupported request body type: ${typeof body}`);
19
+ }
20
+ function makeResponse(status, body) {
21
+ return new Response(Uint8Array.from(body), { status });
22
+ }
23
+ function makeChunkStream(chunks) {
24
+ let index = 0;
25
+ return new ReadableStream({
26
+ pull(controller) {
27
+ const chunk = chunks[index];
28
+ if (!chunk) {
29
+ controller.close();
30
+ return;
31
+ }
32
+ controller.enqueue(chunk);
33
+ index += 1;
34
+ },
35
+ });
36
+ }
37
+ async function readStreamBytes(stream) {
38
+ const reader = stream.getReader();
39
+ const chunks = [];
40
+ while (true) {
41
+ const next = await reader.read();
42
+ if (next.done) {
43
+ break;
44
+ }
45
+ chunks.push(Buffer.from(next.value));
46
+ }
47
+ return Buffer.concat(chunks);
48
+ }
49
+ function makeFakeFetch(sequence) {
50
+ const calls = [];
51
+ const queue = [...sequence];
52
+ const fakeFetch = async (input, init) => {
53
+ calls.push({ input, init });
54
+ const next = queue.shift();
55
+ if (!next) {
56
+ throw new Error('No fake fetch result configured');
57
+ }
58
+ if (next instanceof Error) {
59
+ throw next;
60
+ }
61
+ return next;
62
+ };
63
+ return { fakeFetch, calls };
64
+ }
65
+ describe('unary transport', () => {
66
+ it('unary posts bytes and returns response bytes', async () => {
67
+ const { fakeFetch, calls } = makeFakeFetch([makeResponse(200, responseBytes)]);
68
+ const transport = new DevstralTransport({ fetch: fakeFetch });
69
+ const headers = new Headers({ 'content-type': 'application/grpc+proto' });
70
+ const output = await transport.postUnary('https://api.test/unary', requestBytes, headers);
71
+ expect(output).toEqual(responseBytes);
72
+ expect(calls).toHaveLength(1);
73
+ expect(calls[0]?.input).toBe('https://api.test/unary');
74
+ expect(calls[0]?.init?.method).toBe('POST');
75
+ expect(calls[0]?.init?.headers).toBe(headers);
76
+ expect(bufferFromBody(calls[0]?.init?.body)).toEqual(requestBytes);
77
+ });
78
+ it('unary retries 5xx responses and eventually succeeds', async () => {
79
+ const { fakeFetch, calls } = makeFakeFetch([
80
+ makeResponse(500, Buffer.from('first-failure')),
81
+ makeResponse(502, Buffer.from('second-failure')),
82
+ makeResponse(200, responseBytes),
83
+ ]);
84
+ const transport = new DevstralTransport({ fetch: fakeFetch });
85
+ const output = await transport.postUnary('https://api.test/unary', requestBytes, new Headers());
86
+ expect(output).toEqual(responseBytes);
87
+ expect(calls).toHaveLength(3);
88
+ });
89
+ });
90
+ describe('streaming transport', () => {
91
+ it('streaming posts bytes and returns response stream without pre-buffering', async () => {
92
+ let arrayBufferCalled = false;
93
+ const streamingBody = makeChunkStream([
94
+ Uint8Array.from([9, 8]),
95
+ Uint8Array.from([7, 6]),
96
+ ]);
97
+ const streamingResponse = {
98
+ ok: true,
99
+ status: 200,
100
+ body: streamingBody,
101
+ arrayBuffer: async () => {
102
+ arrayBufferCalled = true;
103
+ throw new Error('arrayBuffer should not be called for streaming responses');
104
+ },
105
+ };
106
+ const { fakeFetch, calls } = makeFakeFetch([streamingResponse]);
107
+ const transport = new DevstralTransport({ fetch: fakeFetch });
108
+ const headers = new Headers({ accept: 'application/connect+proto' });
109
+ const output = await transport.postStreaming('https://api.test/stream', requestBytes, headers);
110
+ expect(output).toBe(streamingBody);
111
+ expect(await readStreamBytes(output)).toEqual(responseBytes);
112
+ expect(arrayBufferCalled).toBe(false);
113
+ expect(calls).toHaveLength(1);
114
+ expect(calls[0]?.input).toBe('https://api.test/stream');
115
+ expect(calls[0]?.init?.method).toBe('POST');
116
+ expect(calls[0]?.init?.headers).toBe(headers);
117
+ expect(bufferFromBody(calls[0]?.init?.body)).toEqual(requestBytes);
118
+ });
119
+ it('streaming throws NETWORK_ERROR when response body stream is missing', async () => {
120
+ const responseWithoutBody = {
121
+ ok: true,
122
+ status: 200,
123
+ body: null,
124
+ arrayBuffer: async () => Buffer.alloc(0),
125
+ };
126
+ const { fakeFetch } = makeFakeFetch([responseWithoutBody]);
127
+ const transport = new DevstralTransport({ fetch: fakeFetch });
128
+ await expect(transport.postStreaming('https://api.test/stream', requestBytes, new Headers())).rejects.toMatchObject({
129
+ code: 'NETWORK_ERROR',
130
+ message: 'Streaming response body is unavailable',
131
+ });
132
+ });
133
+ it('streaming uses AbortSignal to cancel request', async () => {
134
+ const controller = new AbortController();
135
+ const abortedError = new Error('Request aborted');
136
+ abortedError.name = 'AbortError';
137
+ const calls = [];
138
+ const fakeFetch = async (input, init) => {
139
+ calls.push({ input, init });
140
+ if (init?.signal?.aborted) {
141
+ throw abortedError;
142
+ }
143
+ return makeResponse(200, responseBytes);
144
+ };
145
+ const transport = new DevstralTransport({ fetch: fakeFetch });
146
+ controller.abort();
147
+ await expect(transport.postStreaming('https://api.test/stream', requestBytes, new Headers(), controller.signal)).rejects.toMatchObject({ name: 'AbortError' });
148
+ expect(calls).toHaveLength(1);
149
+ expect(calls[0]?.init?.signal).toBe(controller.signal);
150
+ });
151
+ });
152
+ describe('error classification', () => {
153
+ it('error maps 403 to AUTH_ERROR without retrying', async () => {
154
+ const { fakeFetch, calls } = makeFakeFetch([makeResponse(403, Buffer.from('forbidden'))]);
155
+ const transport = new DevstralTransport({ fetch: fakeFetch });
156
+ await expect(transport.postUnary('https://api.test/unary', requestBytes, new Headers())).rejects.toMatchObject({ code: 'AUTH_ERROR' });
157
+ expect(calls).toHaveLength(1);
158
+ });
159
+ it('error maps 429 to RATE_LIMITED without retrying', async () => {
160
+ const { fakeFetch, calls } = makeFakeFetch([makeResponse(429, Buffer.from('limited'))]);
161
+ const transport = new DevstralTransport({ fetch: fakeFetch });
162
+ await expect(transport.postUnary('https://api.test/unary', requestBytes, new Headers())).rejects.toMatchObject({ code: 'RATE_LIMITED' });
163
+ expect(calls).toHaveLength(1);
164
+ });
165
+ it('error maps network failures to NETWORK_ERROR', async () => {
166
+ const { fakeFetch, calls } = makeFakeFetch([new Error('socket hang up')]);
167
+ const transport = new DevstralTransport({ fetch: fakeFetch });
168
+ await expect(transport.postUnary('https://api.test/unary', requestBytes, new Headers())).rejects.toMatchObject({ code: 'NETWORK_ERROR' });
169
+ expect(calls).toHaveLength(1);
170
+ });
171
+ it('error does not downgrade https requests on TLS failures', async () => {
172
+ const calls = [];
173
+ const fakeFetch = async (input, init) => {
174
+ calls.push({ input, init });
175
+ throw new Error('TLS certificate verify failed');
176
+ };
177
+ const transport = new DevstralTransport({ fetch: fakeFetch });
178
+ const request = transport.postUnary('https://api.test/unary', requestBytes, new Headers());
179
+ await expect(request).rejects.toBeInstanceOf(DevstralTransportError);
180
+ await expect(request).rejects.toMatchObject({ code: 'NETWORK_ERROR' });
181
+ expect(calls).toHaveLength(1);
182
+ expect(calls[0]?.input).toBe('https://api.test/unary');
183
+ });
184
+ it('error retries 5xx responses before throwing NETWORK_ERROR', async () => {
185
+ const { fakeFetch, calls } = makeFakeFetch([
186
+ makeResponse(500, Buffer.from('fail-1')),
187
+ makeResponse(500, Buffer.from('fail-2')),
188
+ makeResponse(503, Buffer.from('fail-3')),
189
+ ]);
190
+ const transport = new DevstralTransport({ fetch: fakeFetch });
191
+ await expect(transport.postUnary('https://api.test/unary', requestBytes, new Headers())).rejects.toMatchObject({ code: 'NETWORK_ERROR' });
192
+ expect(calls).toHaveLength(3);
193
+ });
194
+ });
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,6 @@
1
+ export default {
2
+ test: {
3
+ globals: false,
4
+ passWithNoTests: true,
5
+ },
6
+ };
package/dist/index.cjs ADDED
@@ -0,0 +1,2 @@
1
+ exports.__esModule = true;
2
+ module.exports = require('./cjs/index.js');
@@ -0,0 +1,3 @@
1
+ export * from './types/index.js';
2
+ export { createWindsurfProvider, windsurf } from './provider.js';
3
+ export { default } from './provider.js';
package/dist/index.js ADDED
@@ -0,0 +1 @@
1
+ export * from './esm/index.js';
@@ -0,0 +1,118 @@
1
+ import { JwtManager } from '../auth/jwt-manager.js';
2
+ import { type LanguageModelV3Prompt } from '../conversion/prompt-converter.js';
3
+ import { DevstralTransport } from '../transport/http.js';
4
+ import type { WindsurfProviderOptions } from '../types/index.js';
5
+ export interface LanguageModelV3FunctionTool {
6
+ description?: string;
7
+ parameters?: unknown;
8
+ }
9
+ export interface LanguageModelV3CallOptions {
10
+ prompt: LanguageModelV3Prompt;
11
+ tools?: Record<string, LanguageModelV3FunctionTool>;
12
+ abortSignal?: AbortSignal;
13
+ }
14
+ export interface LanguageModelV3GenerateResult {
15
+ content: GenerateContentPart[];
16
+ finishReason: {
17
+ unified: 'stop';
18
+ raw: string | undefined;
19
+ };
20
+ usage: {
21
+ inputTokens: {
22
+ total: number | undefined;
23
+ noCache: number | undefined;
24
+ cacheRead: number | undefined;
25
+ cacheWrite: number | undefined;
26
+ };
27
+ outputTokens: {
28
+ total: number | undefined;
29
+ text: number | undefined;
30
+ reasoning: number | undefined;
31
+ };
32
+ };
33
+ warnings: unknown[];
34
+ }
35
+ export interface LanguageModelV3StreamResult {
36
+ stream: ReadableStream<LanguageModelV3StreamPart>;
37
+ }
38
+ interface LanguageModelV3ToolCallContent {
39
+ type: 'tool-call';
40
+ toolCallType: 'function';
41
+ toolCallId: string;
42
+ toolName: string;
43
+ args: string;
44
+ }
45
+ type GenerateContentPart = {
46
+ type: 'text';
47
+ text: string;
48
+ } | LanguageModelV3ToolCallContent;
49
+ type LanguageModelV3StreamPart = {
50
+ type: 'stream-start';
51
+ warnings: unknown[];
52
+ } | {
53
+ type: 'response-metadata';
54
+ modelId: string;
55
+ } | {
56
+ type: 'text-start';
57
+ id: string;
58
+ } | {
59
+ type: 'text-delta';
60
+ id: string;
61
+ delta: string;
62
+ } | {
63
+ type: 'text-end';
64
+ id: string;
65
+ } | {
66
+ type: 'tool-input-start';
67
+ toolCallId: string;
68
+ toolName: string;
69
+ } | {
70
+ type: 'tool-input-delta';
71
+ toolCallId: string;
72
+ delta: string;
73
+ } | {
74
+ type: 'tool-input-end';
75
+ toolCallId: string;
76
+ } | LanguageModelV3ToolCallContent | {
77
+ type: 'error';
78
+ error: unknown;
79
+ } | {
80
+ type: 'finish';
81
+ finishReason: {
82
+ unified: 'stop';
83
+ raw: string | undefined;
84
+ };
85
+ usage: {
86
+ inputTokens: {
87
+ total: number | undefined;
88
+ noCache: number | undefined;
89
+ cacheRead: number | undefined;
90
+ cacheWrite: number | undefined;
91
+ };
92
+ outputTokens: {
93
+ total: number | undefined;
94
+ text: number | undefined;
95
+ reasoning: number | undefined;
96
+ };
97
+ };
98
+ };
99
+ export interface DevstralLanguageModelOptions extends WindsurfProviderOptions {
100
+ modelId?: string;
101
+ transport?: DevstralTransport;
102
+ jwtManager?: JwtManager;
103
+ }
104
+ export declare class DevstralLanguageModel {
105
+ readonly specificationVersion = "v3";
106
+ readonly provider = "windsurf";
107
+ readonly modelId: string;
108
+ readonly supportedUrls: Record<string, RegExp[]>;
109
+ private readonly apiKey;
110
+ private readonly baseURL;
111
+ private readonly headers;
112
+ private readonly transport;
113
+ private readonly jwtManager;
114
+ constructor(options?: DevstralLanguageModelOptions);
115
+ doGenerate(options: LanguageModelV3CallOptions): Promise<LanguageModelV3GenerateResult>;
116
+ doStream(options: LanguageModelV3CallOptions): Promise<LanguageModelV3StreamResult>;
117
+ }
118
+ export {};
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,10 @@
1
+ /**
2
+ * Encode a protobuf payload into a Connect-RPC frame.
3
+ *
4
+ * @param payload - The raw protobuf bytes to encode
5
+ * @param compress - Whether to gzip-compress the payload (default: true)
6
+ * When true, the payload is gzipped and flags=1 is set
7
+ * @returns Buffer containing: [flags byte][4-byte length][payload (gzipped if compress=true)]
8
+ */
9
+ export declare function connectFrameEncode(payload: Buffer, compress?: boolean): Buffer;
10
+ export declare function connectFrameDecode(buffer: Buffer): Buffer[];
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,11 @@
1
+ export declare class ProtobufEncoder {
2
+ private readonly chunks;
3
+ writeVarint(field: number, value: number): void;
4
+ writeString(field: number, value: string): void;
5
+ writeBytes(field: number, data: Buffer): void;
6
+ writeMessage(field: number, encoder: ProtobufEncoder): void;
7
+ toBuffer(): Buffer;
8
+ private writeTag;
9
+ }
10
+ export declare function decodeVarint(buffer: Buffer, offset: number): [value: number, newOffset: number];
11
+ export declare function extractStrings(buffer: Buffer): string[];
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,5 @@
1
+ import { DevstralLanguageModel } from './model/devstral-language-model.js';
2
+ import type { WindsurfProviderOptions } from './types/index.js';
3
+ export declare function createWindsurfProvider(options?: WindsurfProviderOptions): (modelId?: string) => DevstralLanguageModel;
4
+ export declare const windsurf: (modelId?: string) => DevstralLanguageModel;
5
+ export default windsurf;
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,22 @@
1
+ type FetchLike = (input: string | URL | Request, init?: RequestInit) => Promise<Response>;
2
+ export type DevstralTransportErrorCode = 'AUTH_ERROR' | 'RATE_LIMITED' | 'NETWORK_ERROR';
3
+ export declare class DevstralTransportError extends Error {
4
+ readonly code: DevstralTransportErrorCode;
5
+ readonly status?: number;
6
+ constructor(code: DevstralTransportErrorCode, message: string, status?: number, options?: ErrorOptions);
7
+ }
8
+ export interface DevstralTransportOptions {
9
+ fetch?: FetchLike;
10
+ maxAttempts?: number;
11
+ }
12
+ export declare class DevstralTransport {
13
+ private readonly fetchFn;
14
+ private readonly maxAttempts;
15
+ constructor(options?: DevstralTransportOptions);
16
+ postUnary(url: string, body: Buffer, headers: Headers): Promise<Buffer>;
17
+ postStreaming(url: string, body: Buffer, headers: Headers, signal?: AbortSignal): Promise<ReadableStream<Uint8Array>>;
18
+ private postUnaryRequest;
19
+ private postStreamingRequest;
20
+ private post;
21
+ }
22
+ export {};
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,37 @@
1
+ export interface WindsurfProviderOptions {
2
+ apiKey?: string;
3
+ baseURL?: string;
4
+ headers?: Record<string, string>;
5
+ fetch?: FetchFn;
6
+ generateId?: () => string;
7
+ }
8
+ export type FetchFn = (input: string | URL | Request, init?: RequestInit) => Promise<Response>;
9
+ export interface Tool<Input = unknown, Output = unknown> {
10
+ id: string;
11
+ name?: string;
12
+ run?: (input: Input) => Promise<Output> | Output;
13
+ }
14
+ export interface Model {
15
+ id: string;
16
+ name?: string;
17
+ metadata?: Record<string, unknown>;
18
+ }
19
+ export interface Protocol {
20
+ send(request: string): Promise<string>;
21
+ }
22
+ export type DevstralRole = 1 | 2 | 4 | 5;
23
+ export interface DevstralMetadata {
24
+ [key: string]: unknown;
25
+ }
26
+ export interface DevstralMessage {
27
+ id?: string;
28
+ role: DevstralRole;
29
+ content: string;
30
+ metadata?: DevstralMetadata;
31
+ }
32
+ export interface DevstralToolDefinition {
33
+ id: string;
34
+ name?: string;
35
+ description?: string;
36
+ }
37
+ export type WindsurfModelId = 'MODEL_SWE_1_6_FAST' | 'MODEL_SWE_1_6' | string;
package/package.json ADDED
@@ -0,0 +1,51 @@
1
+ {
2
+ "name": "@bxb1337/windsurf-fast-context",
3
+ "version": "1.0.0",
4
+ "description": "AI SDK V3 provider for Windsurf's Devstral code search API",
5
+ "type": "module",
6
+ "scripts": {
7
+ "test": "vitest --run",
8
+ "build:types": "tsc -p tsconfig.types.json",
9
+ "build:esm": "tsc -p tsconfig.json",
10
+ "build:cjs": "tsc -p tsconfig.cjs.json",
11
+ "build": "pnpm -s run build:types && pnpm -s run build:esm && pnpm -s run build:cjs && node ./scripts/postbuild.js",
12
+ "typecheck": "tsc -p tsconfig.json --noEmit"
13
+ },
14
+ "keywords": [
15
+ "windsurf",
16
+ "devstral",
17
+ "ai-sdk",
18
+ "code-search",
19
+ "llm",
20
+ "provider"
21
+ ],
22
+ "author": "",
23
+ "license": "MIT",
24
+ "repository": {
25
+ "type": "git",
26
+ "url": "https://github.com/bxb1337/windsurf-fast-context"
27
+ },
28
+ "devDependencies": {
29
+ "ai": "^6.0.116",
30
+ "typescript": "^5.0.0",
31
+ "vitest": "^1.0.0"
32
+ },
33
+ "peerDependencies": {
34
+ "ai": ">=4.0.0"
35
+ },
36
+ "main": "dist/index.cjs",
37
+ "module": "dist/index.js",
38
+ "types": "dist/index.d.ts",
39
+ "exports": {
40
+ ".": {
41
+ "import": "./dist/index.js",
42
+ "require": "./dist/index.cjs",
43
+ "types": "./dist/index.d.ts"
44
+ }
45
+ },
46
+ "files": [
47
+ "dist",
48
+ "README.md",
49
+ "LICENSE"
50
+ ]
51
+ }