@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.
- package/index.js +58 -45
- 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.
|
|
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
|
-
|
|
28
|
-
|
|
29
|
-
|
|
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
|
|
33
|
-
choice.finish_reason
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
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
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
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
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
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
|
|
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
|
-
|
|
68
|
-
} else {
|
|
69
|
-
delete parsed.usage;
|
|
89
|
+
cleaned.usage = { prompt_tokens, completion_tokens, total_tokens };
|
|
70
90
|
}
|
|
71
91
|
}
|
|
72
92
|
|
|
73
|
-
|
|
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
|
-
|
|
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
|
-
|
|
127
|
-
|
|
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
|
-
|
|
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
|
}
|