@serii84/vertex-partner-provider 1.0.22 → 1.0.24

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 (2) hide show
  1. package/index.js +58 -45
  2. package/package.json +1 -1
package/index.js CHANGED
@@ -1,9 +1,20 @@
1
1
  /**
2
2
  * Vertex Partner Provider for OpenCode
3
- * v1.0.22 - Fix: remove null values from delta, remove empty usage
3
+ * v1.0.24 - Debug: write to file instead of console
4
4
  */
5
5
 
6
+ const fs = require('fs');
7
+ const path = require('path');
8
+
6
9
  const DEBUG = process.env.VERTEX_DEBUG === 'true';
10
+ const DEBUG_FILE = process.env.VERTEX_DEBUG_FILE || '/tmp/vertex-debug.log';
11
+
12
+ function debugLog(...args) {
13
+ if (!DEBUG) return;
14
+ const timestamp = new Date().toISOString();
15
+ const message = args.map(a => typeof a === 'string' ? a : JSON.stringify(a, null, 2)).join(' ');
16
+ fs.appendFileSync(DEBUG_FILE, `[${timestamp}] ${message}\n`);
17
+ }
7
18
 
8
19
  const { createOpenAICompatible } = require('@ai-sdk/openai-compatible');
9
20
  const { GoogleAuth } = require('google-auth-library');
@@ -23,56 +34,63 @@ async function getAuthToken(googleAuthOptions) {
23
34
  }
24
35
 
25
36
  function cleanResponse(parsed) {
37
+ // Build a clean response with only standard OpenAI fields
38
+ const cleaned = {
39
+ id: parsed.id,
40
+ object: parsed.object,
41
+ created: parsed.created,
42
+ model: parsed.model,
43
+ };
44
+
26
45
  if (parsed.choices) {
27
- for (const choice of parsed.choices) {
28
- delete choice.matched_stop;
29
- delete choice.logprobs;
46
+ cleaned.choices = parsed.choices.map(choice => {
47
+ const cleanChoice = {
48
+ index: choice.index,
49
+ };
30
50
 
31
51
  // Normalize finish_reason to a string (some models return an object)
32
- if (choice.finish_reason && typeof choice.finish_reason === 'object') {
33
- choice.finish_reason = choice.finish_reason.type
34
- || choice.finish_reason.reason
35
- || choice.finish_reason.stop_reason
36
- || 'stop';
52
+ if (choice.finish_reason != null) {
53
+ if (typeof choice.finish_reason === 'object') {
54
+ cleanChoice.finish_reason = choice.finish_reason.type
55
+ || choice.finish_reason.reason
56
+ || choice.finish_reason.stop_reason
57
+ || 'stop';
58
+ } else {
59
+ cleanChoice.finish_reason = choice.finish_reason;
60
+ }
37
61
  }
38
62
 
39
63
  // Clean up delta - remove null values and non-standard fields
40
64
  if (choice.delta) {
41
- if (!choice.delta.content && choice.delta.reasoning_content) {
42
- choice.delta.content = choice.delta.reasoning_content;
43
- }
44
- delete choice.delta.reasoning_content;
45
-
46
- // Remove null values from delta - OpenAI format uses empty object, not nulls
47
- for (const key of Object.keys(choice.delta)) {
48
- if (choice.delta[key] === null) {
49
- delete choice.delta[key];
50
- }
51
- }
65
+ const cleanDelta = {};
66
+ if (choice.delta.role) cleanDelta.role = choice.delta.role;
67
+ if (choice.delta.content) cleanDelta.content = choice.delta.content;
68
+ else if (choice.delta.reasoning_content) cleanDelta.content = choice.delta.reasoning_content;
69
+ if (choice.delta.tool_calls) cleanDelta.tool_calls = choice.delta.tool_calls;
70
+ cleanChoice.delta = cleanDelta;
52
71
  }
53
72
 
54
73
  if (choice.message) {
55
- if (!choice.message.content && choice.message.reasoning_content) {
56
- choice.message.content = choice.message.reasoning_content;
57
- }
58
- delete choice.message.reasoning_content;
74
+ const cleanMessage = { role: choice.message.role };
75
+ if (choice.message.content) cleanMessage.content = choice.message.content;
76
+ else if (choice.message.reasoning_content) cleanMessage.content = choice.message.reasoning_content;
77
+ if (choice.message.tool_calls) cleanMessage.tool_calls = choice.message.tool_calls;
78
+ cleanChoice.message = cleanMessage;
59
79
  }
60
- }
80
+
81
+ return cleanChoice;
82
+ });
61
83
  }
62
84
 
63
- // Clean usage - only keep standard fields, remove if empty/invalid
85
+ // Clean usage - only keep standard fields
64
86
  if (parsed.usage) {
65
87
  const { prompt_tokens, completion_tokens, total_tokens } = parsed.usage;
66
88
  if (prompt_tokens != null || completion_tokens != null || total_tokens != null) {
67
- parsed.usage = { prompt_tokens, completion_tokens, total_tokens };
68
- } else {
69
- delete parsed.usage;
89
+ cleaned.usage = { prompt_tokens, completion_tokens, total_tokens };
70
90
  }
71
91
  }
72
92
 
73
- delete parsed.metadata;
74
-
75
- return parsed;
93
+ return cleaned;
76
94
  }
77
95
 
78
96
  function transformStream(response) {
@@ -112,26 +130,21 @@ function transformStream(response) {
112
130
  try {
113
131
  const parsed = JSON.parse(data);
114
132
 
115
- if (DEBUG) {
116
- console.log('[VERTEX DEBUG] Raw chunk:', JSON.stringify(parsed, null, 2));
117
- }
118
-
119
- // Skip empty choices (usage-only chunk)
120
- if (parsed.choices && parsed.choices.length === 0) {
121
- continue;
122
- }
133
+ debugLog('Raw chunk:', parsed);
123
134
 
124
135
  const cleaned = cleanResponse(parsed);
125
136
 
126
- if (DEBUG) {
127
- console.log('[VERTEX DEBUG] Cleaned chunk:', JSON.stringify(cleaned, null, 2));
137
+ // Skip chunks that have no useful data after cleaning
138
+ if ((!cleaned.choices || cleaned.choices.length === 0) && !cleaned.usage) {
139
+ debugLog('Skipping empty chunk');
140
+ continue;
128
141
  }
129
142
 
143
+ debugLog('Cleaned chunk:', cleaned);
144
+
130
145
  controller.enqueue(encoder.encode('data: ' + JSON.stringify(cleaned) + '\n\n'));
131
146
  } catch (e) {
132
- if (DEBUG) {
133
- console.log('[VERTEX DEBUG] JSON parse error:', e.message, 'Data:', data);
134
- }
147
+ debugLog('JSON parse error:', e.message, 'Data:', data);
135
148
  // Skip invalid JSON
136
149
  }
137
150
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@serii84/vertex-partner-provider",
3
- "version": "1.0.22",
3
+ "version": "1.0.24",
4
4
  "description": "Vertex AI partner models (GLM, Kimi, DeepSeek) for OpenCode",
5
5
  "main": "index.js",
6
6
  "scripts": {