@bxb1337/windsurf-fast-context 1.0.1 → 1.0.3

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.
@@ -5,6 +5,8 @@ const node_zlib_1 = require("node:zlib");
5
5
  const protobuf_js_1 = require("../protocol/protobuf.js");
6
6
  const TOOL_CALL_PREFIX = '[TOOL_CALLS]';
7
7
  const ARGS_PREFIX = '[ARGS]';
8
+ const STOP_TOKEN = '</s>';
9
+ const EMPTY_TOOL_CALLS_PATTERN = /TOOL_CALLS\d*<\/s>\s*\{\}/g;
8
10
  function pushText(parts, text) {
9
11
  if (text.length > 0) {
10
12
  parts.push({ type: 'text', text });
@@ -189,7 +191,9 @@ function decodeResponseText(buffer) {
189
191
  return pickBestExtractedText(extracted);
190
192
  }
191
193
  function convertResponse(buffer) {
192
- const responseText = decodeResponseText(buffer);
194
+ let responseText = decodeResponseText(buffer);
195
+ responseText = responseText.replace(EMPTY_TOOL_CALLS_PATTERN, '');
196
+ responseText = responseText.replace(STOP_TOKEN, '');
193
197
  const parts = [];
194
198
  let cursor = 0;
195
199
  let toolCallCount = 0;
@@ -62,4 +62,19 @@ const response_converter_js_1 = require("./response-converter.js");
62
62
  const result = (0, response_converter_js_1.convertResponse)(compressed);
63
63
  (0, vitest_1.expect)(result).toEqual([{ type: 'text', text: 'hello from gzip' }]);
64
64
  });
65
+ (0, vitest_1.it)('strips empty TOOL_CALLS markers with stop token', () => {
66
+ const input = 'Hello world TOOL_CALLS0</s>{}';
67
+ const result = (0, response_converter_js_1.convertResponse)(Buffer.from(input, 'utf8'));
68
+ (0, vitest_1.expect)(result).toEqual([{ type: 'text', text: 'Hello world ' }]);
69
+ });
70
+ (0, vitest_1.it)('strips standalone stop token', () => {
71
+ const input = 'Hello world</s>';
72
+ const result = (0, response_converter_js_1.convertResponse)(Buffer.from(input, 'utf8'));
73
+ (0, vitest_1.expect)(result).toEqual([{ type: 'text', text: 'Hello world' }]);
74
+ });
75
+ (0, vitest_1.it)('handles TOOL_CALLS with number prefix before stop token', () => {
76
+ const input = 'Text before TOOL_CALLS1</s>{} text after';
77
+ const result = (0, response_converter_js_1.convertResponse)(Buffer.from(input, 'utf8'));
78
+ (0, vitest_1.expect)(result).toEqual([{ type: 'text', text: 'Text before text after' }]);
79
+ });
65
80
  });
@@ -61,7 +61,7 @@ class DevstralLanguageModel {
61
61
  const content = payloads.flatMap((payload) => toV3Content((0, response_converter_js_1.convertResponse)(payload)));
62
62
  return {
63
63
  content,
64
- finishReason: { unified: 'stop', raw: 'stop' },
64
+ finishReason: 'stop',
65
65
  usage: emptyUsage(),
66
66
  warnings: [],
67
67
  };
@@ -163,7 +163,8 @@ class DevstralLanguageModel {
163
163
  closeTextSegment();
164
164
  safeEnqueue(controller, {
165
165
  type: 'finish',
166
- finishReason: { unified: 'stop', raw: 'stop' },
166
+ finishReason: 'stop',
167
+ rawFinishReason: 'stop',
167
168
  usage: emptyUsage(),
168
169
  });
169
170
  safeClose(controller);
@@ -177,7 +178,8 @@ class DevstralLanguageModel {
177
178
  });
178
179
  safeEnqueue(controller, {
179
180
  type: 'finish',
180
- finishReason: { unified: 'stop', raw: 'stop' },
181
+ finishReason: 'error',
182
+ rawFinishReason: 'error',
181
183
  usage: emptyUsage(),
182
184
  });
183
185
  }
@@ -136,7 +136,7 @@ async function collectStreamParts(stream) {
136
136
  prompt: [{ role: 'user', content: [{ type: 'text', text: 'Find auth logic.' }] }],
137
137
  });
138
138
  (0, vitest_1.expect)(result.content).toEqual([{ type: 'text', text: 'generated answer' }]);
139
- (0, vitest_1.expect)(result.finishReason).toEqual({ unified: 'stop', raw: 'stop' });
139
+ (0, vitest_1.expect)(result.finishReason).toBe('stop');
140
140
  (0, vitest_1.expect)(result.usage).toEqual({
141
141
  inputTokens: {
142
142
  total: undefined,
@@ -290,7 +290,8 @@ async function collectStreamParts(stream) {
290
290
  (0, vitest_1.expect)(parts[4]).toMatchObject({ type: 'text-delta', delta: 'world' });
291
291
  (0, vitest_1.expect)(parts[6]).toEqual({
292
292
  type: 'finish',
293
- finishReason: { unified: 'stop', raw: 'stop' },
293
+ finishReason: 'stop',
294
+ rawFinishReason: 'stop',
294
295
  usage: {
295
296
  inputTokens: {
296
297
  total: undefined,
@@ -2,6 +2,8 @@ import { gunzipSync } from 'node:zlib';
2
2
  import { extractStrings } from '../protocol/protobuf.js';
3
3
  const TOOL_CALL_PREFIX = '[TOOL_CALLS]';
4
4
  const ARGS_PREFIX = '[ARGS]';
5
+ const STOP_TOKEN = '</s>';
6
+ const EMPTY_TOOL_CALLS_PATTERN = /TOOL_CALLS\d*<\/s>\s*\{\}/g;
5
7
  function pushText(parts, text) {
6
8
  if (text.length > 0) {
7
9
  parts.push({ type: 'text', text });
@@ -186,7 +188,9 @@ function decodeResponseText(buffer) {
186
188
  return pickBestExtractedText(extracted);
187
189
  }
188
190
  export function convertResponse(buffer) {
189
- const responseText = decodeResponseText(buffer);
191
+ let responseText = decodeResponseText(buffer);
192
+ responseText = responseText.replace(EMPTY_TOOL_CALLS_PATTERN, '');
193
+ responseText = responseText.replace(STOP_TOKEN, '');
190
194
  const parts = [];
191
195
  let cursor = 0;
192
196
  let toolCallCount = 0;
@@ -60,4 +60,19 @@ describe('convertResponse', () => {
60
60
  const result = convertResponse(compressed);
61
61
  expect(result).toEqual([{ type: 'text', text: 'hello from gzip' }]);
62
62
  });
63
+ it('strips empty TOOL_CALLS markers with stop token', () => {
64
+ const input = 'Hello world TOOL_CALLS0</s>{}';
65
+ const result = convertResponse(Buffer.from(input, 'utf8'));
66
+ expect(result).toEqual([{ type: 'text', text: 'Hello world ' }]);
67
+ });
68
+ it('strips standalone stop token', () => {
69
+ const input = 'Hello world</s>';
70
+ const result = convertResponse(Buffer.from(input, 'utf8'));
71
+ expect(result).toEqual([{ type: 'text', text: 'Hello world' }]);
72
+ });
73
+ it('handles TOOL_CALLS with number prefix before stop token', () => {
74
+ const input = 'Text before TOOL_CALLS1</s>{} text after';
75
+ const result = convertResponse(Buffer.from(input, 'utf8'));
76
+ expect(result).toEqual([{ type: 'text', text: 'Text before text after' }]);
77
+ });
63
78
  });
@@ -58,7 +58,7 @@ export class DevstralLanguageModel {
58
58
  const content = payloads.flatMap((payload) => toV3Content(convertResponse(payload)));
59
59
  return {
60
60
  content,
61
- finishReason: { unified: 'stop', raw: 'stop' },
61
+ finishReason: 'stop',
62
62
  usage: emptyUsage(),
63
63
  warnings: [],
64
64
  };
@@ -160,7 +160,8 @@ export class DevstralLanguageModel {
160
160
  closeTextSegment();
161
161
  safeEnqueue(controller, {
162
162
  type: 'finish',
163
- finishReason: { unified: 'stop', raw: 'stop' },
163
+ finishReason: 'stop',
164
+ rawFinishReason: 'stop',
164
165
  usage: emptyUsage(),
165
166
  });
166
167
  safeClose(controller);
@@ -174,7 +175,8 @@ export class DevstralLanguageModel {
174
175
  });
175
176
  safeEnqueue(controller, {
176
177
  type: 'finish',
177
- finishReason: { unified: 'stop', raw: 'stop' },
178
+ finishReason: 'error',
179
+ rawFinishReason: 'error',
178
180
  usage: emptyUsage(),
179
181
  });
180
182
  }
@@ -134,7 +134,7 @@ describe('DevstralLanguageModel doGenerate', () => {
134
134
  prompt: [{ role: 'user', content: [{ type: 'text', text: 'Find auth logic.' }] }],
135
135
  });
136
136
  expect(result.content).toEqual([{ type: 'text', text: 'generated answer' }]);
137
- expect(result.finishReason).toEqual({ unified: 'stop', raw: 'stop' });
137
+ expect(result.finishReason).toBe('stop');
138
138
  expect(result.usage).toEqual({
139
139
  inputTokens: {
140
140
  total: undefined,
@@ -288,7 +288,8 @@ describe('DevstralLanguageModel doStream', () => {
288
288
  expect(parts[4]).toMatchObject({ type: 'text-delta', delta: 'world' });
289
289
  expect(parts[6]).toEqual({
290
290
  type: 'finish',
291
- finishReason: { unified: 'stop', raw: 'stop' },
291
+ finishReason: 'stop',
292
+ rawFinishReason: 'stop',
292
293
  usage: {
293
294
  inputTokens: {
294
295
  total: undefined,
@@ -13,10 +13,7 @@ export interface LanguageModelV3CallOptions {
13
13
  }
14
14
  export interface LanguageModelV3GenerateResult {
15
15
  content: GenerateContentPart[];
16
- finishReason: {
17
- unified: 'stop';
18
- raw: string | undefined;
19
- };
16
+ finishReason: 'stop' | 'length' | 'content-filter' | 'tool-calls' | 'error' | 'other';
20
17
  usage: {
21
18
  inputTokens: {
22
19
  total: number | undefined;
@@ -78,10 +75,8 @@ type LanguageModelV3StreamPart = {
78
75
  error: unknown;
79
76
  } | {
80
77
  type: 'finish';
81
- finishReason: {
82
- unified: 'stop';
83
- raw: string | undefined;
84
- };
78
+ finishReason: 'stop' | 'length' | 'content-filter' | 'tool-calls' | 'error' | 'other';
79
+ rawFinishReason: string | undefined;
85
80
  usage: {
86
81
  inputTokens: {
87
82
  total: number | undefined;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@bxb1337/windsurf-fast-context",
3
- "version": "1.0.1",
3
+ "version": "1.0.3",
4
4
  "description": "AI SDK V3 provider for Windsurf's Devstral code search API",
5
5
  "type": "module",
6
6
  "scripts": {