bingocode 1.0.20 → 1.0.22

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.
@@ -409,8 +409,8 @@ export class ProviderService {
409
409
  }
410
410
 
411
411
  try {
412
- const fetchOpts = getProxyFetchOptions()
413
- const res = await fetch(url, { headers, signal: AbortSignal.timeout(10000), ...fetchOpts })
412
+ const directOpts = getDirectFetchOptions()
413
+ const res = await fetch(url, { headers, signal: AbortSignal.timeout(10000), ...directOpts })
414
414
  if (!res.ok) {
415
415
  console.error(`[ProviderService] Failed to fetch models from ${url}: ${res.status}`)
416
416
  return []
@@ -438,11 +438,26 @@ export class ProviderService {
438
438
 
439
439
  // If no modelId provided, try to fetch from provider or use preset default
440
440
  let modelId = overrides?.modelId || provider.models.main
441
- if (!modelId || modelId === 'auto' || modelId.startsWith('claude-')) {
442
- const fetched = await this.fetchProviderModels(id).catch(() => [])
443
- if (fetched.length > 0) {
444
- modelId = fetched[0] // Use first available model for testing
445
- }
441
+ const needsAutoDetect =
442
+ !modelId ||
443
+ modelId === 'auto' ||
444
+ (apiFormat !== 'anthropic' && modelId.startsWith('claude-'))
445
+ if (needsAutoDetect) {
446
+ const fetched = await this.fetchProviderModels(id).catch(() => [])
447
+ if (fetched.length > 0) {
448
+ modelId = fetched[0] // Use first available model for testing
449
+ }
450
+ }
451
+
452
+ // 兜底:如果仍然没有有效的 modelId,直接返回有意义的错误
453
+ if (!modelId) {
454
+ return {
455
+ connectivity: {
456
+ success: false,
457
+ latencyMs: 0,
458
+ error: '无法确定测试用模型:models.main 为空且自动拉取模型列表失败。请先在槽位配置中选择模型,或检查 API Key 和网络连接。',
459
+ },
460
+ }
446
461
  }
447
462
 
448
463
  if (!baseUrl || !provider.apiKey) {
@@ -491,7 +506,6 @@ export class ProviderService {
491
506
  const start = Date.now()
492
507
  try {
493
508
  const { url, headers, body } = buildDirectTestRequest(base, apiKey, modelId, format)
494
- // 使用 getDirectFetchOptions 以绕开系统代理,测试直接连接
495
509
  const directOpts = getDirectFetchOptions()
496
510
  const response = await fetch(url, {
497
511
  method: 'POST',
@@ -556,13 +570,13 @@ export class ProviderService {
556
570
  }
557
571
 
558
572
  // Call upstream with transformed request
559
- const fetchOpts = getProxyFetchOptions()
573
+ const directOpts = getDirectFetchOptions()
560
574
  const response = await fetch(upstreamUrl, {
561
575
  method: 'POST',
562
576
  headers: { 'Content-Type': 'application/json', Authorization: `Bearer ${apiKey}` },
563
577
  body: JSON.stringify(transformedBody),
564
578
  signal: AbortSignal.timeout(30000),
565
- ...fetchOpts,
579
+ ...directOpts,
566
580
  })
567
581
 
568
582
  if (!response.ok) {
package/src/utils/auth.ts CHANGED
@@ -88,7 +88,7 @@ const DEFAULT_API_KEY_HELPER_TTL = 5 * 60 * 1000
88
88
  * who runs `claude` in their terminal with an API key sees every CCD session
89
89
  * also use that key — and fail if it's stale/wrong-org.
90
90
  */
91
- function isManagedOAuthContext(): boolean {
91
+ export function isManagedOAuthContext(): boolean {
92
92
  return (
93
93
  isEnvTruthy(process.env.CLAUDE_CODE_REMOTE) ||
94
94
  process.env.CLAUDE_CODE_ENTRYPOINT === 'claude-desktop'
@@ -1344,17 +1344,11 @@ export function enableConfigs(): void {
1344
1344
  // to prevent us from adding config reading during module initialization
1345
1345
  configReadingAllowed = true
1346
1346
  // We only check the global config because currently all the configs share a file
1347
- try {
1348
- getConfig(
1349
- getGlobalClaudeFile(),
1350
- createDefaultGlobalConfig,
1351
- true /* throw on invalid */,
1352
- )
1353
- } catch (e) {
1354
- logForDebugging(`Failed to load config during enableConfigs: ${e}`, { level: 'error' })
1355
- // If it's a corrupted file, we allow the boostrap to continue with defaults
1356
- // instead of hard-crashing the process.
1357
- }
1347
+ getConfig(
1348
+ getGlobalClaudeFile(),
1349
+ createDefaultGlobalConfig,
1350
+ true /* throw on invalid */,
1351
+ )
1358
1352
 
1359
1353
  logForDiagnosticsNoPII('info', 'enable_configs_completed', {
1360
1354
  duration_ms: Date.now() - startTime,
@@ -202,7 +202,7 @@ export function PreflightStep(t0) {
202
202
 
203
203
  //@C:ID=F.PC._temp;K=F;V=1.0;P=Helper function for process exit;D=UI;M=Connectivity;S=Utility;In=void;Out=void
204
204
  function _temp() {
205
- console.log("F.PC._temp: Skipping force exit on connectivity failure.");
206
-
207
- // return process.exit(1);
205
+ console.log("F.PC._temp");
206
+
207
+ return process.exit(1);
208
208
  }
@@ -334,26 +334,14 @@ export function getDirectFetchOptions(): {
334
334
  return { ...base, proxy: undefined, ...getTLSFetchOptions() }
335
335
  }
336
336
 
337
- // Check if system proxy exists
338
- const proxyUrl = getProxyUrl()
339
- if (!proxyUrl) {
340
- // No proxy configured, just return normal fetch options
341
- return { ...base, ...getTLSFetchOptions() }
342
- }
343
-
344
337
  // In Node.js/undici, a fresh Agent with no proxy settings bypasses system defaults
345
338
  // eslint-disable-next-line @typescript-eslint/no-require-imports
346
339
  const undiciMod = require('undici') as typeof undici
347
340
  const tlsOpts = getTLSFetchOptions()
348
341
 
349
- // Use the global dispatcher's options if possible, or fresh default options
350
- const agentOptions = tlsOpts.dispatcher && 'options' in (tlsOpts.dispatcher as any)
351
- ? (tlsOpts.dispatcher as any).options
352
- : {}
353
-
354
342
  return {
355
343
  ...base,
356
- dispatcher: new undiciMod.Agent(agentOptions),
344
+ dispatcher: new undiciMod.Agent(tlsOpts.dispatcher ? (tlsOpts.dispatcher as any).options : {}),
357
345
  }
358
346
  }
359
347
 
@@ -1,56 +0,0 @@
1
- /**
2
- * Anthropic-to-Anthropic SSE stream labeler.
3
- *
4
- * Intercepts an Anthropic Messages API stream and replaces the 'model' field
5
- * in the 'message_start' event with a custom label.
6
- */
7
-
8
- export function anthropicStreamLabeler(
9
- upstream: ReadableStream<Uint8Array>,
10
- label: string,
11
- ): ReadableStream<Uint8Array> {
12
- const encoder = new TextEncoder()
13
- const decoder = new TextDecoder()
14
- let buffer = ''
15
-
16
- return new ReadableStream({
17
- async start(controller) {
18
- const reader = upstream.getReader()
19
- try {
20
- while (true) {
21
- const { done, value } = await reader.read()
22
- if (done) break
23
-
24
- buffer += decoder.decode(value, { stream: true })
25
- const lines = buffer.split('\n')
26
- buffer = lines.pop() || ''
27
-
28
- for (const line of lines) {
29
- const trimmed = line.trim()
30
- if (!trimmed || !trimmed.startsWith('data: ')) {
31
- controller.enqueue(encoder.encode(line + '\n'))
32
- continue
33
- }
34
-
35
- const jsonStr = trimmed.slice(6)
36
- try {
37
- const data = JSON.parse(jsonStr)
38
- if (data.type === 'message_start' && data.message) {
39
- data.message.model = label
40
- controller.enqueue(encoder.encode(`data: ${JSON.stringify(data)}\n`))
41
- } else {
42
- controller.enqueue(encoder.encode(line + '\n'))
43
- }
44
- } catch {
45
- controller.enqueue(encoder.encode(line + '\n'))
46
- }
47
- }
48
- }
49
- } catch (err) {
50
- controller.error(err)
51
- } finally {
52
- controller.close()
53
- }
54
- },
55
- })
56
- }