@lay111/dsh-plugin-google 1.0.16 → 1.0.18

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/package.json CHANGED
@@ -1,12 +1,17 @@
1
1
  {
2
2
  "name": "@lay111/dsh-plugin-google",
3
- "version": "1.0.16",
3
+ "version": "1.0.18",
4
4
  "description": "Community-driven DeepSeek Harness Plugin for Google Antigravity & Gemini/Claude Models",
5
5
  "type": "module",
6
6
  "main": "src/index.js",
7
7
  "exports": {
8
8
  ".": "./src/index.js",
9
- "./package.json": "./package.json"
9
+ "./package.json": "./package.json",
10
+ "./auth": "./src/auth.js",
11
+ "./models": "./src/models.js",
12
+ "./api": "./src/api.js",
13
+ "./adapter": "./src/adapter.js",
14
+ "./src/*": "./src/*"
10
15
  },
11
16
  "bin": {
12
17
  "dsh-plugin-google": "bin/setup.js",
package/src/api.js CHANGED
@@ -8,37 +8,62 @@ const ANTIGRAVITY_ENDPOINTS = [
8
8
 
9
9
  export function cleanSchema(schema) {
10
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);
11
+ if (Array.isArray(schema)) return schema.map(cleanSchema);
12
+
13
+ // Handle anyOf / oneOf (Google Gemini rejects siblings with anyOf)
14
+ if (Array.isArray(schema.anyOf) || Array.isArray(schema.oneOf)) {
15
+ const variants = schema.anyOf || schema.oneOf;
16
+ const nonNull = variants.find((v) => v && v.type !== 'null') || variants[0];
17
+ const isNullable = variants.some((v) => v && v.type === 'null');
18
+ const merged = cleanSchema(nonNull);
19
+ if (isNullable && typeof merged === 'object' && merged !== null) merged.nullable = true;
20
+ return merged;
21
+ }
22
+
23
+ const cleaned = {};
24
+
25
+ // Normalize type array e.g. ["string", "null"] -> type: "string", nullable: true
26
+ if (Array.isArray(schema.type)) {
27
+ const hasNull = schema.type.includes('null');
28
+ const mainType = schema.type.find((t) => t !== 'null') || 'string';
29
+ cleaned.type = mainType;
30
+ if (hasNull) cleaned.nullable = true;
31
+ } else if (schema.type) {
32
+ cleaned.type = schema.type;
33
+ }
34
+
35
+ if (typeof schema.description === 'string' && schema.description.length > 0) {
36
+ cleaned.description = schema.description;
37
+ }
38
+
39
+ if (schema.nullable === true) {
40
+ cleaned.nullable = true;
41
+ }
42
+
43
+ if (typeof schema.format === 'string' && schema.format.length > 0) {
44
+ cleaned.format = schema.format;
45
+ }
46
+
47
+ if (Array.isArray(schema.enum)) {
48
+ cleaned.enum = schema.enum;
49
+ }
50
+
51
+ if (Array.isArray(schema.required)) {
52
+ cleaned.required = schema.required;
53
+ }
54
+
55
+ if (schema.properties && typeof schema.properties === 'object' && !Array.isArray(schema.properties)) {
56
+ cleaned.properties = {};
57
+ for (const [k, v] of Object.entries(schema.properties)) {
58
+ cleaned.properties[k] = cleanSchema(v);
37
59
  }
38
60
  }
39
61
 
40
- clean(clone);
41
- return clone;
62
+ if (schema.items && typeof schema.items === 'object') {
63
+ cleaned.items = cleanSchema(schema.items);
64
+ }
65
+
66
+ return cleaned;
42
67
  }
43
68
 
44
69
  export function formatMessagesToAntigravity(messages, modelSpec, projectId) {
@@ -223,7 +248,12 @@ export async function* streamAntigravity(options, accessToken, projectId) {
223
248
  const reader = response.body.getReader();
224
249
  const decoder = new TextDecoder();
225
250
  let buffer = '';
226
- let blockIndex = 0;
251
+ let hasText = false;
252
+ let hasToolCall = false;
253
+ let accumulatedThoughts = '';
254
+ let nextBlockIndex = 0;
255
+ const reasoningBlockIndex = 0;
256
+ let textBlockIndex = 1;
227
257
 
228
258
  try {
229
259
  while (true) {
@@ -250,22 +280,26 @@ export async function* streamAntigravity(options, accessToken, projectId) {
250
280
 
251
281
  for (const part of candidate.content?.parts || []) {
252
282
  if (part.thought) {
283
+ accumulatedThoughts += part.text || '';
253
284
  yield {
254
285
  type: 'reasoning-delta',
255
- index: blockIndex,
286
+ index: reasoningBlockIndex,
256
287
  text: part.text || '',
257
288
  };
258
289
  } else if (part.text) {
290
+ hasText = true;
259
291
  yield {
260
292
  type: 'text-delta',
261
- index: blockIndex,
293
+ index: textBlockIndex,
262
294
  text: part.text || '',
263
295
  };
264
296
  } else if (part.functionCall) {
297
+ hasToolCall = true;
265
298
  const callId = `call_${Math.random().toString(36).slice(2, 10)}`;
299
+ const callIndex = 2 + (nextBlockIndex++);
266
300
  yield {
267
301
  type: 'tool-call-delta',
268
- index: blockIndex++,
302
+ index: callIndex,
269
303
  id: callId,
270
304
  name: part.functionCall.name,
271
305
  argumentsDelta: JSON.stringify(part.functionCall.args || {}),
@@ -274,6 +308,17 @@ export async function* streamAntigravity(options, accessToken, projectId) {
274
308
  }
275
309
 
276
310
  if (candidate.finishReason) {
311
+ // Fallback protection: If the model only thought and emitted 0 text and 0 tool calls,
312
+ // synthesize a completion text so the turn never cuts off silently!
313
+ if (!hasText && !hasToolCall && accumulatedThoughts.length > 0) {
314
+ hasText = true;
315
+ yield {
316
+ type: 'text-delta',
317
+ index: textBlockIndex,
318
+ text: '\n(已完成思考,请指示下一步)',
319
+ };
320
+ }
321
+
277
322
  yield {
278
323
  type: 'finish',
279
324
  reason: 'stop',
@@ -285,6 +330,19 @@ export async function* streamAntigravity(options, accessToken, projectId) {
285
330
  }
286
331
  }
287
332
  }
333
+
334
+ // Final safety check
335
+ if (!hasText && !hasToolCall && accumulatedThoughts.length > 0) {
336
+ yield {
337
+ type: 'text-delta',
338
+ index: textBlockIndex,
339
+ text: '\n(已完成思考,请指示下一步)',
340
+ };
341
+ yield {
342
+ type: 'finish',
343
+ reason: 'stop',
344
+ };
345
+ }
288
346
  } finally {
289
347
  reader.releaseLock();
290
348
  }
package/src/index.js CHANGED
@@ -1,5 +1,10 @@
1
1
  import { AntigravityLlmAdapter } from './adapter.js';
2
2
 
3
+ export * from './auth.js';
4
+ export * from './models.js';
5
+ export * from './api.js';
6
+ export * from './adapter.js';
7
+
3
8
  export const name = 'dsh-antigravity';
4
9
  export const inject = ['llm'];
5
10
 
package/src/models.js CHANGED
@@ -1,4 +1,14 @@
1
1
  export const ANTIGRAVITY_MODELS = [
2
+ {
3
+ id: 'gemini-3.8-flash',
4
+ name: 'Gemini 3.8 Flash High (Thinking)',
5
+ wireId: 'gemini-3.8-flash-high',
6
+ contextWindow: 1048576,
7
+ maxTokens: 65536,
8
+ supportsThinking: true,
9
+ thinkingBudget: 10000,
10
+ description: 'Google flagship coding model with 10k thinking budget (Fast & Deep)',
11
+ },
2
12
  {
3
13
  id: 'gemini-3.7-flash',
4
14
  name: 'Gemini 3.7 Flash High (Thinking)',