forked from NoeFabris/opencode-antigravity-auth
-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathschema.ts
More file actions
502 lines (442 loc) · 16.9 KB
/
Copy pathschema.ts
File metadata and controls
502 lines (442 loc) · 16.9 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
/**
* Configuration schema for opencode-antigravity-auth plugin.
*
* Config file locations (in priority order, highest wins):
* - Project: .opencode/antigravity.json
* - User: ~/.config/opencode/antigravity.json (Linux/Mac)
* %APPDATA%\opencode\antigravity.json (Windows)
*
* Environment variables always override config file values.
*/
import { z } from "zod";
/**
* Account selection strategy for distributing requests across accounts.
*
* - `sticky`: Use same account until rate-limited. Preserves prompt cache.
* - `round-robin`: Rotate to next account on every request. Maximum throughput.
* - `hybrid` (default): Deterministic selection based on health score + token bucket + LRU freshness.
*/
export const AccountSelectionStrategySchema = z.enum(['sticky', 'round-robin', 'hybrid']);
export type AccountSelectionStrategy = z.infer<typeof AccountSelectionStrategySchema>;
/**
* Toast notification scope for controlling which sessions show toasts.
*
* - `root_only` (default): Only show toasts for root sessions (no parentID).
* Subagents and background tasks won't show toast notifications.
* - `all`: Show toasts for all sessions including subagents and background tasks.
*/
export const ToastScopeSchema = z.enum(['root_only', 'all']);
export type ToastScope = z.infer<typeof ToastScopeSchema>;
/**
* Scheduling mode for rate limit behavior.
*
* - `cache_first`: Wait for same account to recover (preserves prompt cache). Default.
* - `balance`: Switch account immediately on rate limit. Maximum availability.
* - `performance_first`: Round-robin distribution for maximum throughput.
*/
export const SchedulingModeSchema = z.enum(['cache_first', 'balance', 'performance_first']);
export type SchedulingMode = z.infer<typeof SchedulingModeSchema>;
/**
* Signature cache configuration for persisting thinking block signatures to disk.
*/
export const SignatureCacheConfigSchema = z.object({
/** Enable disk caching of signatures (default: true) */
enabled: z.boolean().default(true),
/** In-memory TTL in seconds (default: 3600 = 1 hour) */
memory_ttl_seconds: z.number().min(60).max(86400).default(3600),
/** Disk TTL in seconds (default: 172800 = 48 hours) */
disk_ttl_seconds: z.number().min(3600).max(604800).default(172800),
/** Background write interval in seconds (default: 60) */
write_interval_seconds: z.number().min(10).max(600).default(60),
});
/**
* Main configuration schema for the Antigravity OAuth plugin.
*/
export const AntigravityConfigSchema = z.object({
/** JSON Schema reference for IDE support */
$schema: z.string().optional(),
// =========================================================================
// General Settings
// =========================================================================
/**
* Suppress most toast notifications (rate limit, account switching, etc.)
* Recovery toasts are always shown regardless of this setting.
* Env override: OPENCODE_ANTIGRAVITY_QUIET=1
* @default false
*/
quiet_mode: z.boolean().default(false),
/**
* Control which sessions show toast notifications.
*
* - `root_only` (default): Only root sessions show toasts.
* Subagents and background tasks will be silent (less spam).
* - `all`: All sessions show toasts including subagents and background tasks.
*
* Debug logging captures all toasts regardless of this setting.
* Env override: OPENCODE_ANTIGRAVITY_TOAST_SCOPE=all
* @default "root_only"
*/
toast_scope: ToastScopeSchema.default('root_only'),
/**
* Enable debug logging to file.
* Env override: OPENCODE_ANTIGRAVITY_DEBUG=1
* @default false
*/
debug: z.boolean().default(false),
/**
* Show debug logs in the TUI log panel.
* Works independently from `debug` file logging.
* Env override: OPENCODE_ANTIGRAVITY_DEBUG_TUI=1
* @default false
*/
debug_tui: z.boolean().default(false),
/**
* Custom directory for debug logs.
* Env override: OPENCODE_ANTIGRAVITY_LOG_DIR=/path/to/logs
* @default OS-specific config dir + "/antigravity-logs"
*/
log_dir: z.string().optional(),
// =========================================================================
// Thinking Blocks
// =========================================================================
/**
* Preserve thinking blocks for Claude models using signature caching.
*
* When false (default): Thinking blocks are stripped for reliability.
* When true: Full context preserved, but may encounter signature errors.
*
* Env override: OPENCODE_ANTIGRAVITY_KEEP_THINKING=1
* @default false
*/
keep_thinking: z.boolean().default(false),
// =========================================================================
// Session Recovery
// =========================================================================
/**
* Enable automatic session recovery from tool_result_missing errors.
* When enabled, shows a toast notification when recoverable errors occur.
*
* @default true
*/
session_recovery: z.boolean().default(true),
/**
* Automatically send a "continue" prompt after successful recovery.
* Only applies when session_recovery is enabled.
*
* When false: Only shows toast notification, user must manually continue.
* When true: Automatically sends "continue" to resume the session.
*
* @default false
*/
auto_resume: z.boolean().default(false),
/**
* Custom text to send when auto-resuming after recovery.
* Only used when auto_resume is enabled.
*
* @default "continue"
*/
resume_text: z.string().default("continue"),
// =========================================================================
// Signature Caching
// =========================================================================
/**
* Signature cache configuration for persisting thinking block signatures.
* Only used when keep_thinking is enabled.
*/
signature_cache: SignatureCacheConfigSchema.optional(),
// =========================================================================
// Empty Response Retry (ported from LLM-API-Key-Proxy)
// =========================================================================
/**
* Maximum retry attempts when Antigravity returns an empty response.
* Empty responses occur when no candidates/choices are returned.
*
* @default 4
*/
empty_response_max_attempts: z.number().min(1).max(10).default(4),
/**
* Delay in milliseconds between empty response retries.
*
* @default 2000
*/
empty_response_retry_delay_ms: z.number().min(500).max(10000).default(2000),
// =========================================================================
// Tool ID Recovery (ported from LLM-API-Key-Proxy)
// =========================================================================
/**
* Enable tool ID orphan recovery.
* When tool responses have mismatched IDs (due to context compaction),
* attempt to match them by function name or create placeholders.
*
* @default true
*/
tool_id_recovery: z.boolean().default(true),
// =========================================================================
// Tool Hallucination Prevention (ported from LLM-API-Key-Proxy)
// =========================================================================
/**
* Enable tool hallucination prevention for Claude models.
* When enabled, injects:
* - Parameter signatures into tool descriptions
* - System instruction with strict tool usage rules
*
* This helps prevent Claude from using parameter names from its training
* data instead of the actual schema.
*
* @default true
*/
claude_tool_hardening: z.boolean().default(true),
/**
* Enable Claude prompt auto-caching by adding top-level cache_control when absent.
*
* @default false
*/
claude_prompt_auto_caching: z.boolean().default(false),
// =========================================================================
// Proactive Token Refresh (ported from LLM-API-Key-Proxy)
// =========================================================================
/**
* Enable proactive background token refresh.
* When enabled, tokens are refreshed in the background before they expire,
* ensuring requests never block on token refresh.
*
* @default true
*/
proactive_token_refresh: z.boolean().default(true),
/**
* Seconds before token expiry to trigger proactive refresh.
* Default is 30 minutes (1800 seconds).
*
* @default 1800
*/
proactive_refresh_buffer_seconds: z.number().min(60).max(7200).default(1800),
/**
* Interval between proactive refresh checks in seconds.
* Default is 5 minutes (300 seconds).
*
* @default 300
*/
proactive_refresh_check_interval_seconds: z.number().min(30).max(1800).default(300),
// =========================================================================
// Rate Limiting
// =========================================================================
/**
* Maximum time in seconds to wait when all accounts are rate-limited.
* If the minimum wait time across all accounts exceeds this threshold,
* the plugin fails fast with an error instead of hanging.
*
* Set to 0 to disable (wait indefinitely).
*
* @default 300 (5 minutes)
*/
max_rate_limit_wait_seconds: z.number().min(0).max(3600).default(300),
/**
* @deprecated Kept only for backward compatibility.
* This flag is ignored at runtime.
* Gemini requests always fall back between Antigravity and Gemini CLI quotas.
*
* @default false
*/
quota_fallback: z.boolean().default(false),
/**
* Prefer gemini-cli routing before Antigravity for Gemini models.
*
* When false (default): Antigravity is tried first, then gemini-cli.
* When true: gemini-cli is tried first, then Antigravity.
*
* @default false
*/
cli_first: z.boolean().default(false),
/**
* Strategy for selecting accounts when making requests.
* Env override: OPENCODE_ANTIGRAVITY_ACCOUNT_SELECTION_STRATEGY
* @default "hybrid"
*/
account_selection_strategy: AccountSelectionStrategySchema.default('hybrid'),
/**
* Enable PID-based account offset for multi-session distribution.
*
* When enabled, different sessions (PIDs) will prefer different starting
* accounts, which helps distribute load when running multiple parallel agents.
*
* When disabled (default), accounts start from the same index, which preserves
* Anthropic's prompt cache across restarts (recommended for single-session use).
*
* Env override: OPENCODE_ANTIGRAVITY_PID_OFFSET_ENABLED=1
* @default false
*/
pid_offset_enabled: z.boolean().default(false),
/**
* Switch to another account immediately on first rate limit (after 1s delay).
* When disabled, retries same account first, then switches on second rate limit.
*
* @default true
*/
switch_on_first_rate_limit: z.boolean().default(true),
/**
* Scheduling mode for rate limit behavior.
*
* - `cache_first`: Wait for same account to recover (preserves prompt cache). Default.
* - `balance`: Switch account immediately on rate limit. Maximum availability.
* - `performance_first`: Round-robin distribution for maximum throughput.
*
* Env override: OPENCODE_ANTIGRAVITY_SCHEDULING_MODE
* @default "cache_first"
*/
scheduling_mode: SchedulingModeSchema.default('cache_first'),
/**
* Maximum seconds to wait for same account in cache_first mode.
* If the account's rate limit reset time exceeds this, switch accounts.
*
* @default 60
*/
max_cache_first_wait_seconds: z.number().min(5).max(300).default(60),
/**
* TTL in seconds for failure count expiration.
* After this period of no failures, consecutiveFailures resets to 0.
* This prevents old failures from permanently penalizing an account.
*
* @default 3600 (1 hour)
*/
failure_ttl_seconds: z.number().min(60).max(7200).default(3600),
/**
* Default retry delay in seconds when API doesn't return a retry-after header.
* Lower values allow faster retries but may trigger more 429 errors.
*
* @default 60
*/
default_retry_after_seconds: z.number().min(1).max(300).default(60),
/**
* Maximum backoff delay in seconds for exponential retry.
* This caps how long the exponential backoff can grow.
*
* @default 60
*/
max_backoff_seconds: z.number().min(5).max(300).default(60),
/**
* Maximum random delay in milliseconds before each API request.
* Adds timing jitter to break predictable request cadence patterns.
* Set to 0 to disable request jitter.
*
* @default 0
*/
request_jitter_max_ms: z.number().min(0).max(5000).default(0),
/**
* Soft quota threshold percentage (1-100).
* When an account's quota usage reaches this percentage, skip it during
* account selection (same as if it were rate-limited).
*
* Example: 90 means skip account when 90% of quota is used (10% remaining).
* Set to 100 to disable soft quota protection.
*
* @default 90
*/
soft_quota_threshold_percent: z.number().min(1).max(100).default(90),
/**
* How often to refresh quota data in the background (in minutes).
* Quota is refreshed opportunistically after successful API requests.
* Set to 0 to disable automatic refresh (manual only via Check quotas).
*
* @default 15
*/
quota_refresh_interval_minutes: z.number().min(0).max(60).default(15),
/**
* How long quota cache is considered fresh for threshold checks (in minutes).
* After this time, cache is stale and account is allowed (fail-open).
*
* "auto" = derive from refresh interval: max(2 * refresh_interval, 10)
*
* @default "auto"
*/
soft_quota_cache_ttl_minutes: z.union([
z.literal("auto"),
z.number().min(1).max(120)
]).default("auto"),
// =========================================================================
// Health Score (used by hybrid strategy)
// =========================================================================
health_score: z.object({
initial: z.number().min(0).max(100).default(70),
success_reward: z.number().min(0).max(10).default(1),
rate_limit_penalty: z.number().min(-50).max(0).default(-10),
failure_penalty: z.number().min(-100).max(0).default(-20),
recovery_rate_per_hour: z.number().min(0).max(20).default(2),
min_usable: z.number().min(0).max(100).default(50),
max_score: z.number().min(50).max(100).default(100),
}).optional(),
// =========================================================================
// Token Bucket (for hybrid strategy)
// =========================================================================
token_bucket: z.object({
max_tokens: z.number().min(1).max(1000).default(50),
regeneration_rate_per_minute: z.number().min(0.1).max(60).default(6),
initial_tokens: z.number().min(1).max(1000).default(50),
}).optional(),
// =========================================================================
// Auto-Update
// =========================================================================
/**
* Enable automatic plugin updates.
* @default true
*/
auto_update: z.boolean().default(true),
});
export type AntigravityConfig = z.infer<typeof AntigravityConfigSchema>;
export type SignatureCacheConfig = z.infer<typeof SignatureCacheConfigSchema>;
/**
* Default configuration values.
*/
export const DEFAULT_CONFIG: AntigravityConfig = {
quiet_mode: false,
toast_scope: 'root_only',
debug: false,
debug_tui: false,
keep_thinking: false,
session_recovery: true,
auto_resume: true,
resume_text: "continue",
empty_response_max_attempts: 4,
empty_response_retry_delay_ms: 2000,
tool_id_recovery: true,
claude_tool_hardening: true,
claude_prompt_auto_caching: false,
proactive_token_refresh: true,
proactive_refresh_buffer_seconds: 1800,
proactive_refresh_check_interval_seconds: 300,
max_rate_limit_wait_seconds: 300,
quota_fallback: false,
cli_first: false,
account_selection_strategy: 'hybrid',
pid_offset_enabled: false,
switch_on_first_rate_limit: true,
scheduling_mode: 'cache_first',
max_cache_first_wait_seconds: 60,
failure_ttl_seconds: 3600,
default_retry_after_seconds: 60,
max_backoff_seconds: 60,
request_jitter_max_ms: 0,
soft_quota_threshold_percent: 90,
quota_refresh_interval_minutes: 15,
soft_quota_cache_ttl_minutes: "auto",
auto_update: true,
signature_cache: {
enabled: true,
memory_ttl_seconds: 3600,
disk_ttl_seconds: 172800,
write_interval_seconds: 60,
},
health_score: {
initial: 70,
success_reward: 1,
rate_limit_penalty: -10,
failure_penalty: -20,
recovery_rate_per_hour: 2,
min_usable: 50,
max_score: 100,
},
token_bucket: {
max_tokens: 50,
regeneration_rate_per_minute: 6,
initial_tokens: 50,
},
};