@lay111/dsh-plugin-google 1.0.15 → 1.0.17

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/package.json +1 -1
  2. package/src/api.js +110 -19
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@lay111/dsh-plugin-google",
3
- "version": "1.0.15",
3
+ "version": "1.0.17",
4
4
  "description": "Community-driven DeepSeek Harness Plugin for Google Antigravity & Gemini/Claude Models",
5
5
  "type": "module",
6
6
  "main": "src/index.js",
package/src/api.js CHANGED
@@ -6,18 +6,58 @@ const ANTIGRAVITY_ENDPOINTS = [
6
6
  'https://daily-cloudcode-pa.sandbox.googleapis.com/v1internal:streamGenerateContent?alt=sse',
7
7
  ];
8
8
 
9
+ export function cleanSchema(schema) {
10
+ if (!schema || typeof schema !== 'object') return schema;
11
+ const clone = JSON.parse(JSON.stringify(schema));
12
+
13
+ function clean(obj) {
14
+ if (!obj || typeof obj !== 'object') return;
15
+ delete obj.$schema;
16
+ delete obj.$id;
17
+ delete obj.definitions;
18
+ delete obj.$defs;
19
+ delete obj.additionalProperties;
20
+
21
+ if (obj.properties && typeof obj.properties === 'object') {
22
+ for (const key of Object.keys(obj.properties)) {
23
+ clean(obj.properties[key]);
24
+ }
25
+ }
26
+ if (obj.items && typeof obj.items === 'object') {
27
+ clean(obj.items);
28
+ }
29
+ if (Array.isArray(obj.anyOf)) {
30
+ obj.anyOf.forEach(clean);
31
+ }
32
+ if (Array.isArray(obj.oneOf)) {
33
+ obj.oneOf.forEach(clean);
34
+ }
35
+ if (Array.isArray(obj.allOf)) {
36
+ obj.allOf.forEach(clean);
37
+ }
38
+ }
39
+
40
+ clean(clone);
41
+ return clone;
42
+ }
43
+
9
44
  export function formatMessagesToAntigravity(messages, modelSpec, projectId) {
10
45
  const contents = [];
11
- let systemInstruction = null;
46
+ const systemParts = [];
47
+ const isClaude = modelSpec.id.includes('claude') || modelSpec.wireId.includes('claude');
12
48
 
13
49
  for (const message of messages) {
14
50
  if (message.role === 'system') {
15
- const text = typeof message.content === 'string' ? message.content : JSON.stringify(message.content);
16
- if (text.length > 0) {
17
- systemInstruction = {
18
- role: 'user',
19
- parts: [{ text }],
20
- };
51
+ let text = '';
52
+ if (typeof message.content === 'string') {
53
+ text = message.content;
54
+ } else if (Array.isArray(message.content)) {
55
+ text = message.content
56
+ .map((b) => (b.type === 'text' ? b.text : typeof b === 'string' ? b : ''))
57
+ .join('\n');
58
+ }
59
+ if (text.trim().length > 0) {
60
+ systemParts.push({ text: text.trim() });
21
61
  }
22
62
  continue;
23
63
  }
@@ -30,24 +70,43 @@ export function formatMessagesToAntigravity(messages, modelSpec, projectId) {
30
70
  } else if (Array.isArray(message.content)) {
31
71
  for (const block of message.content) {
32
72
  if (block.type === 'text') {
33
- parts.push({ text: block.text });
73
+ if (block.text && block.text.length > 0) {
74
+ parts.push({ text: block.text });
75
+ }
34
76
  } else if (block.type === 'thought' || block.type === 'reasoning') {
35
77
  parts.push({ thought: true, text: block.text || block.thought || '' });
36
78
  } else if (block.type === 'tool-call') {
37
- parts.push({
79
+ const callPart = {
38
80
  functionCall: {
39
81
  name: block.name,
40
82
  args: typeof block.arguments === 'string' ? JSON.parse(block.arguments || '{}') : block.arguments || {},
41
83
  },
42
- });
84
+ };
85
+ if (!isClaude) {
86
+ callPart.thoughtSignature = block.thoughtSignature || 'skip_thought_signature_validator';
87
+ }
88
+ parts.push(callPart);
43
89
  } else if (block.type === 'tool-result') {
90
+ let outputText = '';
91
+ if (typeof block.content === 'string') {
92
+ outputText = block.content;
93
+ } else if (Array.isArray(block.content)) {
94
+ outputText = block.content
95
+ .map((p) => p.text || (typeof p === 'string' ? p : JSON.stringify(p)))
96
+ .join('\n');
97
+ } else if (typeof block.content === 'object' && block.content !== null) {
98
+ outputText = JSON.stringify(block.content);
99
+ } else {
100
+ outputText = String(block.content || '');
101
+ }
102
+
44
103
  contents.push({
45
104
  role: 'user',
46
105
  parts: [
47
106
  {
48
107
  functionResponse: {
49
- name: block.name || 'tool',
50
- response: { result: block.content },
108
+ name: block.name || block.toolName || 'tool',
109
+ response: { output: outputText || '(no output)' },
51
110
  },
52
111
  },
53
112
  ],
@@ -68,7 +127,6 @@ export function formatMessagesToAntigravity(messages, modelSpec, projectId) {
68
127
  contents.push({ role: 'user', parts: [{ text: 'Hello' }] });
69
128
  }
70
129
 
71
- const isClaude = modelSpec.id.includes('claude') || modelSpec.wireId.includes('claude');
72
130
  const payload = {
73
131
  project: projectId || 'aicode-consumers',
74
132
  model: modelSpec.wireId,
@@ -86,7 +144,7 @@ export function formatMessagesToAntigravity(messages, modelSpec, projectId) {
86
144
  }
87
145
  : {}),
88
146
  },
89
- ...(systemInstruction ? { systemInstruction } : {}),
147
+ ...(systemParts.length > 0 ? { systemInstruction: { parts: systemParts } } : {}),
90
148
  labels: {
91
149
  trajectory_id: `traj_${Date.now()}`,
92
150
  used_claude: String(isClaude),
@@ -109,7 +167,7 @@ export async function* streamAntigravity(options, accessToken, projectId) {
109
167
  functionDeclarations: options.tools.map((tool) => ({
110
168
  name: tool.name,
111
169
  description: tool.description || '',
112
- parameters: tool.parameters || {},
170
+ parameters: cleanSchema(tool.parameters || {}),
113
171
  })),
114
172
  },
115
173
  ];
@@ -165,7 +223,12 @@ export async function* streamAntigravity(options, accessToken, projectId) {
165
223
  const reader = response.body.getReader();
166
224
  const decoder = new TextDecoder();
167
225
  let buffer = '';
168
- let blockIndex = 0;
226
+ let hasText = false;
227
+ let hasToolCall = false;
228
+ let accumulatedThoughts = '';
229
+ let nextBlockIndex = 0;
230
+ const reasoningBlockIndex = 0;
231
+ let textBlockIndex = 1;
169
232
 
170
233
  try {
171
234
  while (true) {
@@ -192,22 +255,26 @@ export async function* streamAntigravity(options, accessToken, projectId) {
192
255
 
193
256
  for (const part of candidate.content?.parts || []) {
194
257
  if (part.thought) {
258
+ accumulatedThoughts += part.text || '';
195
259
  yield {
196
260
  type: 'reasoning-delta',
197
- index: blockIndex,
261
+ index: reasoningBlockIndex,
198
262
  text: part.text || '',
199
263
  };
200
264
  } else if (part.text) {
265
+ hasText = true;
201
266
  yield {
202
267
  type: 'text-delta',
203
- index: blockIndex,
268
+ index: textBlockIndex,
204
269
  text: part.text || '',
205
270
  };
206
271
  } else if (part.functionCall) {
272
+ hasToolCall = true;
207
273
  const callId = `call_${Math.random().toString(36).slice(2, 10)}`;
274
+ const callIndex = 2 + (nextBlockIndex++);
208
275
  yield {
209
276
  type: 'tool-call-delta',
210
- index: blockIndex++,
277
+ index: callIndex,
211
278
  id: callId,
212
279
  name: part.functionCall.name,
213
280
  argumentsDelta: JSON.stringify(part.functionCall.args || {}),
@@ -216,6 +283,17 @@ export async function* streamAntigravity(options, accessToken, projectId) {
216
283
  }
217
284
 
218
285
  if (candidate.finishReason) {
286
+ // Fallback protection: If the model only thought and emitted 0 text and 0 tool calls,
287
+ // synthesize a completion text so the turn never cuts off silently!
288
+ if (!hasText && !hasToolCall && accumulatedThoughts.length > 0) {
289
+ hasText = true;
290
+ yield {
291
+ type: 'text-delta',
292
+ index: textBlockIndex,
293
+ text: '\n(已完成思考,请指示下一步)',
294
+ };
295
+ }
296
+
219
297
  yield {
220
298
  type: 'finish',
221
299
  reason: 'stop',
@@ -227,6 +305,19 @@ export async function* streamAntigravity(options, accessToken, projectId) {
227
305
  }
228
306
  }
229
307
  }
308
+
309
+ // Final safety check
310
+ if (!hasText && !hasToolCall && accumulatedThoughts.length > 0) {
311
+ yield {
312
+ type: 'text-delta',
313
+ index: textBlockIndex,
314
+ text: '\n(已完成思考,请指示下一步)',
315
+ };
316
+ yield {
317
+ type: 'finish',
318
+ reason: 'stop',
319
+ };
320
+ }
230
321
  } finally {
231
322
  reader.releaseLock();
232
323
  }