codex-overleaf-link 2.0.0 → 2.1.0

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 (119) hide show
  1. package/README.md +24 -23
  2. package/extension/bootstrap/manifest.template.json +2 -1
  3. package/extension/runtime-manifest.json +12 -6
  4. package/extension/src/background.js +7 -0
  5. package/extension/src/content/composerPanel.js +13 -3
  6. package/extension/src/content/contentRuntime.js +129 -64
  7. package/extension/src/content/contextTray.js +173 -9
  8. package/extension/src/content/markdownText.js +16 -1
  9. package/extension/src/content/mathText.js +233 -0
  10. package/extension/src/content/modelPicker.js +117 -106
  11. package/extension/src/content/modelPickerSupport.js +115 -0
  12. package/extension/src/content/nativeChannel.js +20 -1
  13. package/extension/src/content/panelMaintenance.js +2 -0
  14. package/extension/src/content/projectSettingsCoordinator.js +2 -0
  15. package/extension/src/content/providerSettingsCoordinator.js +413 -0
  16. package/extension/src/content/providerSettingsDialog.js +981 -0
  17. package/extension/src/content/runTimelineView.js +24 -5
  18. package/extension/src/content/settingsPanel.js +33 -2
  19. package/extension/src/content/writebackOrchestrator.js +3 -1
  20. package/extension/src/page/overleafProjectSnapshot.js +29 -33
  21. package/extension/src/page/snapshotRouter.js +75 -8
  22. package/extension/src/page/writebackRouter.js +20 -33
  23. package/extension/src/pageBridge.js +1 -1
  24. package/extension/src/shared/agentTranscript.js +130 -0
  25. package/extension/src/shared/compatibility.js +3 -2
  26. package/extension/src/shared/failureReasons.js +75 -0
  27. package/extension/src/shared/i18n.js +22 -0
  28. package/extension/src/shared/models.js +1 -0
  29. package/extension/src/shared/providerProfiles.js +283 -0
  30. package/extension/src/shared/sessionState.js +12 -2
  31. package/extension/src/shared/storageDb.js +1 -1
  32. package/extension/styles/panel.css +587 -1
  33. package/extension/vendor/katex/LICENSE +21 -0
  34. package/extension/vendor/katex/VERSION +2 -0
  35. package/extension/vendor/katex/fonts/KaTeX_AMS-Regular.ttf +0 -0
  36. package/extension/vendor/katex/fonts/KaTeX_AMS-Regular.woff +0 -0
  37. package/extension/vendor/katex/fonts/KaTeX_AMS-Regular.woff2 +0 -0
  38. package/extension/vendor/katex/fonts/KaTeX_Caligraphic-Bold.ttf +0 -0
  39. package/extension/vendor/katex/fonts/KaTeX_Caligraphic-Bold.woff +0 -0
  40. package/extension/vendor/katex/fonts/KaTeX_Caligraphic-Bold.woff2 +0 -0
  41. package/extension/vendor/katex/fonts/KaTeX_Caligraphic-Regular.ttf +0 -0
  42. package/extension/vendor/katex/fonts/KaTeX_Caligraphic-Regular.woff +0 -0
  43. package/extension/vendor/katex/fonts/KaTeX_Caligraphic-Regular.woff2 +0 -0
  44. package/extension/vendor/katex/fonts/KaTeX_Fraktur-Bold.ttf +0 -0
  45. package/extension/vendor/katex/fonts/KaTeX_Fraktur-Bold.woff +0 -0
  46. package/extension/vendor/katex/fonts/KaTeX_Fraktur-Bold.woff2 +0 -0
  47. package/extension/vendor/katex/fonts/KaTeX_Fraktur-Regular.ttf +0 -0
  48. package/extension/vendor/katex/fonts/KaTeX_Fraktur-Regular.woff +0 -0
  49. package/extension/vendor/katex/fonts/KaTeX_Fraktur-Regular.woff2 +0 -0
  50. package/extension/vendor/katex/fonts/KaTeX_Main-Bold.ttf +0 -0
  51. package/extension/vendor/katex/fonts/KaTeX_Main-Bold.woff +0 -0
  52. package/extension/vendor/katex/fonts/KaTeX_Main-Bold.woff2 +0 -0
  53. package/extension/vendor/katex/fonts/KaTeX_Main-BoldItalic.ttf +0 -0
  54. package/extension/vendor/katex/fonts/KaTeX_Main-BoldItalic.woff +0 -0
  55. package/extension/vendor/katex/fonts/KaTeX_Main-BoldItalic.woff2 +0 -0
  56. package/extension/vendor/katex/fonts/KaTeX_Main-Italic.ttf +0 -0
  57. package/extension/vendor/katex/fonts/KaTeX_Main-Italic.woff +0 -0
  58. package/extension/vendor/katex/fonts/KaTeX_Main-Italic.woff2 +0 -0
  59. package/extension/vendor/katex/fonts/KaTeX_Main-Regular.ttf +0 -0
  60. package/extension/vendor/katex/fonts/KaTeX_Main-Regular.woff +0 -0
  61. package/extension/vendor/katex/fonts/KaTeX_Main-Regular.woff2 +0 -0
  62. package/extension/vendor/katex/fonts/KaTeX_Math-BoldItalic.ttf +0 -0
  63. package/extension/vendor/katex/fonts/KaTeX_Math-BoldItalic.woff +0 -0
  64. package/extension/vendor/katex/fonts/KaTeX_Math-BoldItalic.woff2 +0 -0
  65. package/extension/vendor/katex/fonts/KaTeX_Math-Italic.ttf +0 -0
  66. package/extension/vendor/katex/fonts/KaTeX_Math-Italic.woff +0 -0
  67. package/extension/vendor/katex/fonts/KaTeX_Math-Italic.woff2 +0 -0
  68. package/extension/vendor/katex/fonts/KaTeX_SansSerif-Bold.ttf +0 -0
  69. package/extension/vendor/katex/fonts/KaTeX_SansSerif-Bold.woff +0 -0
  70. package/extension/vendor/katex/fonts/KaTeX_SansSerif-Bold.woff2 +0 -0
  71. package/extension/vendor/katex/fonts/KaTeX_SansSerif-Italic.ttf +0 -0
  72. package/extension/vendor/katex/fonts/KaTeX_SansSerif-Italic.woff +0 -0
  73. package/extension/vendor/katex/fonts/KaTeX_SansSerif-Italic.woff2 +0 -0
  74. package/extension/vendor/katex/fonts/KaTeX_SansSerif-Regular.ttf +0 -0
  75. package/extension/vendor/katex/fonts/KaTeX_SansSerif-Regular.woff +0 -0
  76. package/extension/vendor/katex/fonts/KaTeX_SansSerif-Regular.woff2 +0 -0
  77. package/extension/vendor/katex/fonts/KaTeX_Script-Regular.ttf +0 -0
  78. package/extension/vendor/katex/fonts/KaTeX_Script-Regular.woff +0 -0
  79. package/extension/vendor/katex/fonts/KaTeX_Script-Regular.woff2 +0 -0
  80. package/extension/vendor/katex/fonts/KaTeX_Size1-Regular.ttf +0 -0
  81. package/extension/vendor/katex/fonts/KaTeX_Size1-Regular.woff +0 -0
  82. package/extension/vendor/katex/fonts/KaTeX_Size1-Regular.woff2 +0 -0
  83. package/extension/vendor/katex/fonts/KaTeX_Size2-Regular.ttf +0 -0
  84. package/extension/vendor/katex/fonts/KaTeX_Size2-Regular.woff +0 -0
  85. package/extension/vendor/katex/fonts/KaTeX_Size2-Regular.woff2 +0 -0
  86. package/extension/vendor/katex/fonts/KaTeX_Size3-Regular.ttf +0 -0
  87. package/extension/vendor/katex/fonts/KaTeX_Size3-Regular.woff +0 -0
  88. package/extension/vendor/katex/fonts/KaTeX_Size3-Regular.woff2 +0 -0
  89. package/extension/vendor/katex/fonts/KaTeX_Size4-Regular.ttf +0 -0
  90. package/extension/vendor/katex/fonts/KaTeX_Size4-Regular.woff +0 -0
  91. package/extension/vendor/katex/fonts/KaTeX_Size4-Regular.woff2 +0 -0
  92. package/extension/vendor/katex/fonts/KaTeX_Typewriter-Regular.ttf +0 -0
  93. package/extension/vendor/katex/fonts/KaTeX_Typewriter-Regular.woff +0 -0
  94. package/extension/vendor/katex/fonts/KaTeX_Typewriter-Regular.woff2 +0 -0
  95. package/extension/vendor/katex/katex.min.css +1 -0
  96. package/extension/vendor/katex/katex.min.js +1 -0
  97. package/native-host/src/anthropicBridgeRequest.js +435 -0
  98. package/native-host/src/anthropicBridgeResponse.js +431 -0
  99. package/native-host/src/anthropicMessagesBridge.js +281 -0
  100. package/native-host/src/chatBridgeRequest.js +274 -0
  101. package/native-host/src/chatBridgeResponse.js +594 -0
  102. package/native-host/src/chatCompletionsBridge.js +485 -0
  103. package/native-host/src/codexCommand.js +25 -0
  104. package/native-host/src/codexPromptAssembly.js +9 -0
  105. package/native-host/src/codexProviderLaunch.js +213 -0
  106. package/native-host/src/codexProviderTest.js +196 -0
  107. package/native-host/src/codexSessionRunner.js +29 -25
  108. package/native-host/src/managedInstall.js +1 -0
  109. package/native-host/src/providerBridgeRoutes.js +11 -0
  110. package/native-host/src/providerModelCatalog.js +107 -0
  111. package/native-host/src/providerProfile.js +454 -0
  112. package/native-host/src/providerReasoning.js +235 -0
  113. package/native-host/src/providerRedaction.js +18 -0
  114. package/native-host/src/providerRuntime.js +365 -0
  115. package/native-host/src/providerStore.js +691 -0
  116. package/native-host/src/readProgressGuard.js +360 -0
  117. package/native-host/src/taskRunnerRuntime.js +39 -3
  118. package/native-host/src/updateArchive.js +1 -0
  119. package/package.json +2 -1
@@ -584,6 +584,132 @@
584
584
  };
585
585
  }
586
586
 
587
+ function translateProviderError(text, locale) {
588
+ const rules = [
589
+ {
590
+ pattern: /provider_revision_conflict|active provider changed|provider changed in another tab/i,
591
+ conclusionZh: '这轮没有启动:模型服务配置已在另一个标签页发生变化。',
592
+ conclusionEn: 'This run did not start: the model provider configuration changed in another tab.',
593
+ nextZh: '请刷新模型服务配置,然后重新运行任务。',
594
+ nextEn: 'Refresh the provider configuration, then run the task again.',
595
+ code: 'provider_revision_conflict'
596
+ },
597
+ {
598
+ pattern: /provider_auth_rejected|rejected the API key|denied access for this credential/i,
599
+ conclusionZh: '这轮没有继续:第三方模型服务拒绝了当前 API 密钥。',
600
+ conclusionEn: 'This run did not continue: the third-party provider rejected the current API key.',
601
+ nextZh: '请在 Settings 的模型服务配置中替换 API 密钥并测试连接。',
602
+ nextEn: 'Replace the API key in Model Providers and run Test connection.',
603
+ code: 'provider_auth_rejected'
604
+ },
605
+ {
606
+ pattern: /provider_model_not_found|configured model was not found/i,
607
+ conclusionZh: '这轮没有继续:第三方模型服务中找不到所选模型。',
608
+ conclusionEn: 'This run did not continue: the selected model was not found by the third-party provider.',
609
+ nextZh: '请检查模型 ID,测试连接后重试。',
610
+ nextEn: 'Check the model ID, test the connection, and retry.',
611
+ code: 'provider_model_not_found'
612
+ },
613
+ {
614
+ pattern: /provider_model_not_configured|selected model is not configured|at least one model ID is required/i,
615
+ conclusionZh: '这轮没有启动:当前模型没有配置在启用的模型服务中。',
616
+ conclusionEn: 'This run did not start: the current model is not configured for the active provider.',
617
+ nextZh: '请打开模型服务配置,添加或选择一个可用模型。',
618
+ nextEn: 'Open Model Providers and add or select an available model.',
619
+ code: 'provider_model_not_configured'
620
+ },
621
+ {
622
+ pattern: /provider_protocol_unverified|test connection before (activating|using)/i,
623
+ conclusionZh: '这轮没有启动:自动 API 协议尚未完成验证。',
624
+ conclusionEn: 'This run did not start: the automatic API protocol has not been verified.',
625
+ nextZh: '请在模型服务配置中运行“测试连接”,保存后重试。',
626
+ nextEn: 'Run Test connection in Model Providers, save, and retry.',
627
+ code: 'provider_protocol_unverified'
628
+ },
629
+ {
630
+ pattern: /provider_protocol_incompatible|incompatible with this API protocol/i,
631
+ conclusionZh: '这轮没有继续:端点与所选 API 协议不兼容。',
632
+ conclusionEn: 'This run did not continue: the endpoint is incompatible with the selected API protocol.',
633
+ nextZh: '请切换 Responses 或 Chat Completions,或使用自动检测重新测试。',
634
+ nextEn: 'Switch between Responses and Chat Completions, or test again with Auto detection.',
635
+ code: 'provider_protocol_incompatible'
636
+ },
637
+ {
638
+ pattern: /provider_rate_limited|rate limit was reached/i,
639
+ conclusionZh: '这轮没有完成:第三方模型服务触发了限流。',
640
+ conclusionEn: 'This run did not finish: the third-party provider rate limit was reached.',
641
+ nextZh: '请等待限流窗口恢复后重试。',
642
+ nextEn: 'Wait for the provider rate-limit window to recover, then retry.',
643
+ code: 'provider_rate_limited'
644
+ },
645
+ {
646
+ pattern: /provider_connection_timeout|provider connection.*timed out/i,
647
+ conclusionZh: '这轮没有完成:连接第三方模型服务超时。',
648
+ conclusionEn: 'This run did not finish: the third-party provider connection timed out.',
649
+ nextZh: '请检查端点和网络,或提高模型服务的请求超时后重试。',
650
+ nextEn: 'Check the endpoint and network, or increase the provider timeout before retrying.',
651
+ code: 'provider_connection_timeout'
652
+ },
653
+ {
654
+ pattern: /provider_dns_failed|hostname could not be resolved/i,
655
+ conclusionZh: '这轮没有启动:无法解析第三方模型服务的主机名。',
656
+ conclusionEn: 'This run did not start: the third-party provider hostname could not be resolved.',
657
+ nextZh: '请检查 Base URL 和本机 DNS 后重试。',
658
+ nextEn: 'Check the Base URL and local DNS, then retry.',
659
+ code: 'provider_dns_failed'
660
+ },
661
+ {
662
+ pattern: /provider_tls_failed|TLS verification failed/i,
663
+ conclusionZh: '这轮没有启动:第三方模型服务的 TLS 验证失败。',
664
+ conclusionEn: 'This run did not start: TLS verification failed for the third-party provider.',
665
+ nextZh: '请检查端点证书和 Base URL,修复后重试。',
666
+ nextEn: 'Check the endpoint certificate and Base URL, then retry.',
667
+ code: 'provider_tls_failed'
668
+ },
669
+ {
670
+ pattern: /provider_not_found|active provider no longer exists/i,
671
+ conclusionZh: '这轮没有启动:启用的模型服务已经不存在。',
672
+ conclusionEn: 'This run did not start: the active model provider no longer exists.',
673
+ nextZh: '请在 Settings 中选择内置 Codex 或另一个模型服务。',
674
+ nextEn: 'Select Built-in Codex or another provider in Settings.',
675
+ code: 'provider_not_found'
676
+ },
677
+ {
678
+ pattern: /provider_store_corrupt|provider stores are out of sync|provider store.*invalid/i,
679
+ conclusionZh: '这轮没有启动:本地模型服务配置存储已损坏或不同步。',
680
+ conclusionEn: 'This run did not start: the local provider configuration store is corrupt or out of sync.',
681
+ nextZh: '请打开技术详情,修复或重建本地模型服务配置。',
682
+ nextEn: 'Open Technical Details and repair or rebuild the local provider configuration.',
683
+ code: 'provider_store_corrupt'
684
+ },
685
+ {
686
+ pattern: /provider_store_unavailable|provider settings could not be saved/i,
687
+ conclusionZh: '模型服务操作失败:Native Host 无法访问本地配置存储。',
688
+ conclusionEn: 'The provider operation failed: the Native Host could not access local provider storage.',
689
+ nextZh: '请检查本地目录权限和 Native Host 状态后重试。',
690
+ nextEn: 'Check local directory permissions and Native Host status, then retry.',
691
+ code: 'provider_store_unavailable'
692
+ },
693
+ {
694
+ pattern: /provider_response_invalid|provider connection test failed/i,
695
+ conclusionZh: '这轮没有继续:第三方模型服务返回了不兼容或无效的响应。',
696
+ conclusionEn: 'This run did not continue: the third-party provider returned an incompatible or invalid response.',
697
+ nextZh: '请测试连接并确认服务兼容所选 API 协议。',
698
+ nextEn: 'Test the connection and confirm that the endpoint supports the selected API protocol.',
699
+ code: 'provider_response_invalid'
700
+ }
701
+ ];
702
+ const rule = rules.find(candidate => candidate.pattern.test(text));
703
+ if (!rule) {
704
+ return null;
705
+ }
706
+ return {
707
+ conclusion: textFor(locale, rule.conclusionZh, rule.conclusionEn),
708
+ nextStep: textFor(locale, rule.nextZh, rule.nextEn),
709
+ failureCode: rule.code
710
+ };
711
+ }
712
+
587
713
  function translateRawError(message, context = {}) {
588
714
  const locale = normalizeLocale(context);
589
715
  const text = String(message || '');
@@ -594,6 +720,10 @@
594
720
  // failure data alongside the human-readable text. The string text is kept
595
721
  // verbatim because it has mode-aware nuance (e.g. "No files were written"
596
722
  // vs "This run did not start") the catalog's fallback strings don't capture.
723
+ const providerError = translateProviderError(text, locale);
724
+ if (providerError) {
725
+ return providerError;
726
+ }
597
727
  if (/Mode must be "confirm" or "auto"/i.test(text)) {
598
728
  return {
599
729
  conclusion: textFor(locale, '这轮没有写入:当前是“只问不改”,但这个任务需要写入权限。', 'No files were written: this task needs write access, but the current mode is Ask.'),
@@ -12,7 +12,7 @@
12
12
  const MIN_NATIVE_VERSION = '1.0.0';
13
13
  const MIN_COMPATIBLE_NATIVE_VERSION = '1.0.0';
14
14
  const MIN_COMPATIBLE_EXTENSION_VERSION = '1.0.0';
15
- const BUILD_TARGET_VERSION = '2.0.0';
15
+ const BUILD_TARGET_VERSION = '2.1.0';
16
16
  const DEFAULT_CHROME_EXTENSION_ID = 'illdpneeeopfffmiepaejglgmhpmdhdc';
17
17
  const REQUIRED_CAPABILITIES = Object.freeze([
18
18
  'bridgePing',
@@ -24,7 +24,8 @@
24
24
  'codexModels',
25
25
  'historyClearPlugin',
26
26
  'localSkills',
27
- 'mirrorSensitiveScan'
27
+ 'mirrorSensitiveScan',
28
+ 'providerProfiles'
28
29
  ]);
29
30
  const UPDATE_AVAILABLE_CAPABILITIES = Object.freeze([
30
31
  'bridgePing',
@@ -288,6 +288,81 @@
288
288
  fallbackUserMessage: 'Local Codex returned no usable final report or operations.',
289
289
  fallbackNextAction: 'Open Technical Details and resolve the local Codex error.'
290
290
  },
291
+ provider_revision_conflict: {
292
+ stage: 'preflight', severity: 'blocked', defaultRetryable: true,
293
+ fallbackUserMessage: 'The active model provider changed after this tab loaded it.',
294
+ fallbackNextAction: 'Refresh the provider configuration and retry.'
295
+ },
296
+ provider_not_found: {
297
+ stage: 'preflight', severity: 'blocked', defaultRetryable: false,
298
+ fallbackUserMessage: 'The active model provider no longer exists.',
299
+ fallbackNextAction: 'Select Built-in Codex or another provider.'
300
+ },
301
+ provider_model_not_configured: {
302
+ stage: 'preflight', severity: 'blocked', defaultRetryable: false,
303
+ fallbackUserMessage: 'The selected model is not configured for the active provider.',
304
+ fallbackNextAction: 'Add or select a model in Model Providers.'
305
+ },
306
+ provider_protocol_unverified: {
307
+ stage: 'preflight', severity: 'blocked', defaultRetryable: true,
308
+ fallbackUserMessage: 'The provider API protocol has not been verified.',
309
+ fallbackNextAction: 'Run Test connection, save the provider, and retry.'
310
+ },
311
+ provider_auth_rejected: {
312
+ stage: 'codex', severity: 'blocked', defaultRetryable: false,
313
+ fallbackUserMessage: 'The provider rejected the configured API key.',
314
+ fallbackNextAction: 'Replace the API key and test the connection.'
315
+ },
316
+ provider_model_not_found: {
317
+ stage: 'codex', severity: 'blocked', defaultRetryable: false,
318
+ fallbackUserMessage: 'The provider could not find the configured model.',
319
+ fallbackNextAction: 'Correct the model ID and test the connection.'
320
+ },
321
+ provider_protocol_incompatible: {
322
+ stage: 'codex', severity: 'blocked', defaultRetryable: false,
323
+ fallbackUserMessage: 'The endpoint is incompatible with the selected API protocol.',
324
+ fallbackNextAction: 'Select another protocol or use Auto detection.'
325
+ },
326
+ provider_request_rejected: {
327
+ stage: 'codex', severity: 'blocked', defaultRetryable: false,
328
+ fallbackUserMessage: 'The provider rejected the protocol probe request.',
329
+ fallbackNextAction: 'Review the model ID, reasoning controls, tool support, and request overrides.'
330
+ },
331
+ provider_rate_limited: {
332
+ stage: 'codex', severity: 'error', defaultRetryable: true,
333
+ fallbackUserMessage: 'The provider rate limit was reached.',
334
+ fallbackNextAction: 'Wait for the rate-limit window to recover and retry.'
335
+ },
336
+ provider_connection_timeout: {
337
+ stage: 'codex', severity: 'error', defaultRetryable: true,
338
+ fallbackUserMessage: 'The provider connection timed out.',
339
+ fallbackNextAction: 'Check the endpoint and network, then retry.'
340
+ },
341
+ provider_dns_failed: {
342
+ stage: 'codex', severity: 'error', defaultRetryable: true,
343
+ fallbackUserMessage: 'The provider hostname could not be resolved.',
344
+ fallbackNextAction: 'Check the Base URL and DNS, then retry.'
345
+ },
346
+ provider_tls_failed: {
347
+ stage: 'codex', severity: 'error', defaultRetryable: true,
348
+ fallbackUserMessage: 'TLS verification failed for the provider endpoint.',
349
+ fallbackNextAction: 'Check the endpoint certificate and Base URL.'
350
+ },
351
+ provider_response_invalid: {
352
+ stage: 'codex', severity: 'error', defaultRetryable: true,
353
+ fallbackUserMessage: 'The provider returned an incompatible or invalid response.',
354
+ fallbackNextAction: 'Test the connection and verify protocol compatibility.'
355
+ },
356
+ provider_store_unavailable: {
357
+ stage: 'storage', severity: 'error', defaultRetryable: true,
358
+ fallbackUserMessage: 'The Native Host could not access provider configuration storage.',
359
+ fallbackNextAction: 'Check local permissions and Native Host status.'
360
+ },
361
+ provider_store_corrupt: {
362
+ stage: 'storage', severity: 'blocked', defaultRetryable: false,
363
+ fallbackUserMessage: 'The provider configuration store is corrupt or inconsistent.',
364
+ fallbackNextAction: 'Repair or rebuild the local provider configuration.'
365
+ },
291
366
  codex_project_locked: {
292
367
  stage: 'codex', severity: 'blocked', defaultRetryable: true,
293
368
  fallbackUserMessage: 'Another Codex task is already running for this Overleaf project.',
@@ -287,6 +287,11 @@
287
287
  softwareUpdatesTitle: 'Software updates',
288
288
  softwareUpdatesHelp: 'Automatically checks signed stable releases for the Extension and Native Host.',
289
289
  checkForUpdates: 'Check for updates',
290
+ providerSettingsTitle: 'Model providers',
291
+ providerSettingsExperimental: 'Third-party experimental',
292
+ providerSettingsHelp: 'Configure experimental third-party model APIs. Compatibility varies by provider and gateway.',
293
+ providerSettingsConfigure: 'Configure',
294
+ providerSettingsBuiltin: 'Built-in Codex is active',
290
295
  storageUsageLoading: 'Calculating usage\u2026',
291
296
  storageClearAll: 'Clear all history\u2026',
292
297
  storageClearAllHelp: 'Removes every stored session, run and audit record for all projects. Project settings and rules are kept.',
@@ -343,10 +348,16 @@
343
348
  refreshFileList: 'Refresh file list',
344
349
  contextStatus: 'Type @ to add files, or click +: files, attachments (PDF/images), @compile-log.',
345
350
  contextLoadingFiles: 'Reading available @files...',
351
+ contextSyncTreeLoading: 'Reading the project file tree.',
352
+ contextSyncExactLoading: 'Available files are ready. Completing the full ZIP file list.',
353
+ contextSyncExactReady: 'The complete project file list is ready.',
354
+ contextSyncPartial: 'Available files are shown. The complete ZIP file list is unavailable; refresh to retry.',
346
355
  contextReadFailed: 'Could not read files: {message}',
347
356
  contextNoFiles: 'No usable text files were read from this Overleaf project.',
348
357
  contextSelectedFiles: 'Added {count} @file items. Future tasks will focus on them first.',
349
358
  contextDefaultWholeProject: 'Default is the whole project. Add @file; @compile-log and @current-section are available as context options.',
359
+ preloadProjectContextTitle: 'Preload project context',
360
+ preloadProjectContextDescription: 'Fetch the exact project file list in the background after an Overleaf project becomes idle.',
350
361
  contextResourceTitle: '{path} (non-text resource, shown only as project structure for now)',
351
362
  contextWholeProjectChip: 'Default: whole project',
352
363
  clearFiles: 'Clear all @file context',
@@ -762,6 +773,11 @@
762
773
  softwareUpdatesTitle: '软件更新',
763
774
  softwareUpdatesHelp: '自动检查 Extension 与 Native Host 的签名稳定版本。',
764
775
  checkForUpdates: '检查更新',
776
+ providerSettingsTitle: '模型服务',
777
+ providerSettingsExperimental: '第三方实验性',
778
+ providerSettingsHelp: '配置实验性第三方模型 API;兼容性取决于具体模型服务与网关。',
779
+ providerSettingsConfigure: '配置',
780
+ providerSettingsBuiltin: '当前使用内置 Codex',
765
781
  storageUsageLoading: '正在计算占用…',
766
782
  storageClearAll: '清空全部历史…',
767
783
  storageClearAllHelp: '删除所有项目已存储的全部会话、运行与审计记录。项目设置与规则会保留。',
@@ -818,10 +834,16 @@
818
834
  refreshFileList: '刷新文件列表',
819
835
  contextStatus: '输入 @ 添加文件,或点 +:文件、附件(PDF/图片)、@compile-log。',
820
836
  contextLoadingFiles: '正在读取可添加的 @文件...',
837
+ contextSyncTreeLoading: '正在读取项目文件树。',
838
+ contextSyncExactLoading: '可用文件已经显示,正在补齐完整 ZIP 文件列表。',
839
+ contextSyncExactReady: '完整项目文件列表已经就绪。',
840
+ contextSyncPartial: '当前已显示可用文件,完整 ZIP 文件列表暂不可用;可刷新重试。',
821
841
  contextReadFailed: '读取文件失败:{message}',
822
842
  contextNoFiles: '没有从当前 Overleaf 项目读取到可用文本文件。',
823
843
  contextSelectedFiles: '已添加 {count} 个 @file;后续任务会优先围绕它们。',
824
844
  contextDefaultWholeProject: '默认使用整个项目。可添加 @file;@compile-log 和 @current-section 将作为后续上下文能力。',
845
+ preloadProjectContextTitle: '预加载项目上下文',
846
+ preloadProjectContextDescription: 'Overleaf 项目进入空闲状态后,在后台读取精确的项目文件列表。',
825
847
  contextResourceTitle: '{path}(非文本资源,当前只作为项目结构显示)',
826
848
  contextWholeProjectChip: '默认:整个项目',
827
849
  clearFiles: '清除全部 @file',
@@ -63,6 +63,7 @@
63
63
  id,
64
64
  label,
65
65
  reasoningEfforts: Array.isArray(model?.reasoningEfforts) ? model.reasoningEfforts.slice() : [],
66
+ reasoningPresentation: typeof model?.reasoningPresentation === 'string' ? model.reasoningPresentation : '',
66
67
  speedTiers: normalizeSpeedTiers(model?.speedTiers)
67
68
  };
68
69
 
@@ -0,0 +1,283 @@
1
+ (function initCodexOverleafProviderProfiles(root, factory) {
2
+ if (typeof module === 'object' && module.exports) {
3
+ module.exports = factory();
4
+ } else {
5
+ root.CodexOverleafProviderProfiles = factory();
6
+ }
7
+ })(typeof globalThis !== 'undefined' ? globalThis : window, function providerProfilesFactory() {
8
+ 'use strict';
9
+
10
+ const BUILTIN_PROVIDER_ID = 'builtin';
11
+
12
+ function normalizeCatalog(value = {}) {
13
+ const providers = Array.isArray(value.providers)
14
+ ? value.providers.map(normalizeProvider).filter(Boolean)
15
+ : [];
16
+ if (!providers.some(provider => provider.id === BUILTIN_PROVIDER_ID)) {
17
+ providers.unshift(buildBuiltinProvider());
18
+ }
19
+ const requestedActiveId = normalizeText(value.activeProviderId);
20
+ const activeProviderId = providers.some(provider => provider.id === requestedActiveId)
21
+ ? requestedActiveId
22
+ : BUILTIN_PROVIDER_ID;
23
+ return {
24
+ activeProviderId,
25
+ providers,
26
+ storeRevision: normalizeInteger(value.storeRevision)
27
+ };
28
+ }
29
+
30
+ function normalizeProvider(value) {
31
+ if (!value || typeof value !== 'object') {
32
+ return null;
33
+ }
34
+ const id = normalizeText(value.id);
35
+ if (!id) {
36
+ return null;
37
+ }
38
+ if (id === BUILTIN_PROVIDER_ID || value.kind === 'builtin') {
39
+ return buildBuiltinProvider();
40
+ }
41
+ const models = normalizeModels(value.models);
42
+ const defaultModelId = normalizeText(value.defaultModelId) || models[0]?.id || '';
43
+ return {
44
+ id,
45
+ kind: 'custom',
46
+ revision: normalizeInteger(value.revision),
47
+ name: normalizeText(value.name) || 'Custom provider',
48
+ baseUrl: normalizeText(value.baseUrl),
49
+ wireApiPreference: normalizeWireApi(value.wireApiPreference, true),
50
+ resolvedWireApi: normalizeWireApi(value.resolvedWireApi, false),
51
+ models,
52
+ defaultModelId,
53
+ requestTimeoutMs: normalizeInteger(value.requestTimeoutMs) || 30000,
54
+ reasoningAdapter: normalizeReasoningAdapter(value.reasoningAdapter),
55
+ reasoningCapability: normalizeReasoningCapability(value.reasoningCapability),
56
+ authMode: normalizeAuthMode(value.authMode),
57
+ apiKeyHeaderName: normalizeText(value.apiKeyHeaderName),
58
+ fullEndpoint: value.fullEndpoint === true,
59
+ customHeaders: normalizeRecord(value.customHeaders),
60
+ queryParams: normalizeRecord(value.queryParams),
61
+ bodyOverrides: normalizeRecord(value.bodyOverrides),
62
+ contextWindow: normalizeInteger(value.contextWindow) || 262144,
63
+ supportsParallelToolCalls: value.supportsParallelToolCalls === true,
64
+ supportsStreamOptions: value.supportsStreamOptions === true,
65
+ inputModalities: normalizeInputModalities(value.inputModalities),
66
+ anthropicVersion: normalizeText(value.anthropicVersion) || '2023-06-01',
67
+ anthropicBeta: normalizeText(value.anthropicBeta),
68
+ anthropicThinkingMode: normalizeAnthropicThinkingMode(value.anthropicThinkingMode),
69
+ anthropicPromptCaching: value.anthropicPromptCaching === true,
70
+ impersonateClaudeCode: value.impersonateClaudeCode === true,
71
+ maxOutputTokens: normalizeMaxOutputTokens(value.maxOutputTokens),
72
+ hasSecret: value.hasSecret === true,
73
+ secretUpdatedAt: normalizeInteger(value.secretUpdatedAt),
74
+ endpointDisclosureHost: normalizeText(value.endpointDisclosureHost),
75
+ endpointDisclosureBaseUrl: normalizeText(value.endpointDisclosureBaseUrl),
76
+ endpointDisclosureAcceptedAt: normalizeInteger(value.endpointDisclosureAcceptedAt),
77
+ modelDiagnostics: normalizeModelDiagnostics(value.modelDiagnostics),
78
+ lastVerified: value.lastVerified && typeof value.lastVerified === 'object'
79
+ ? {
80
+ revision: normalizeInteger(value.lastVerified.revision),
81
+ at: normalizeInteger(value.lastVerified.at),
82
+ modelId: normalizeText(value.lastVerified.modelId),
83
+ wireApi: normalizeWireApi(value.lastVerified.wireApi, false),
84
+ upstreamResponseMode: normalizeUpstreamResponseMode(value.lastVerified.upstreamResponseMode, false)
85
+ }
86
+ : null,
87
+ createdAt: normalizeInteger(value.createdAt),
88
+ updatedAt: normalizeInteger(value.updatedAt)
89
+ };
90
+ }
91
+
92
+ function normalizeModels(models) {
93
+ if (!Array.isArray(models)) {
94
+ return [];
95
+ }
96
+ const seen = new Set();
97
+ const result = [];
98
+ for (const value of models) {
99
+ const id = normalizeText(typeof value === 'string' ? value : value?.id);
100
+ if (!id || seen.has(id)) {
101
+ continue;
102
+ }
103
+ seen.add(id);
104
+ result.push({
105
+ id,
106
+ label: normalizeText(value?.label) || id,
107
+ reasoningEfforts: Array.isArray(value?.reasoningEfforts)
108
+ ? value.reasoningEfforts.map(normalizeText).filter(Boolean)
109
+ : [],
110
+ upstreamResponseMode: normalizeUpstreamResponseMode(value?.upstreamResponseMode, true),
111
+ resolvedUpstreamResponseMode: normalizeUpstreamResponseMode(value?.resolvedUpstreamResponseMode, false),
112
+ contextWindow: normalizeInteger(value?.contextWindow) || 262144,
113
+ supportsParallelToolCalls: value?.supportsParallelToolCalls === true,
114
+ inputModalities: normalizeInputModalities(value?.inputModalities),
115
+ baseInstructions: normalizeText(value?.baseInstructions)
116
+ });
117
+ }
118
+ return result;
119
+ }
120
+
121
+ function buildBuiltinProvider() {
122
+ return {
123
+ id: BUILTIN_PROVIDER_ID,
124
+ kind: 'builtin',
125
+ revision: 0,
126
+ name: 'Built-in Codex',
127
+ editable: false,
128
+ deletable: false,
129
+ models: []
130
+ };
131
+ }
132
+
133
+ function buildEmptyDraft() {
134
+ return {
135
+ id: '',
136
+ kind: 'custom',
137
+ revision: 0,
138
+ name: 'Custom provider',
139
+ baseUrl: '',
140
+ wireApiPreference: 'auto',
141
+ resolvedWireApi: '',
142
+ models: [],
143
+ defaultModelId: '',
144
+ requestTimeoutMs: 30000,
145
+ reasoningAdapter: 'auto',
146
+ reasoningCapability: 'auto',
147
+ authMode: 'bearer',
148
+ apiKeyHeaderName: '',
149
+ fullEndpoint: false,
150
+ customHeaders: {},
151
+ queryParams: {},
152
+ bodyOverrides: {},
153
+ contextWindow: 262144,
154
+ supportsParallelToolCalls: false,
155
+ supportsStreamOptions: false,
156
+ inputModalities: ['text'],
157
+ anthropicVersion: '2023-06-01',
158
+ anthropicBeta: '',
159
+ anthropicThinkingMode: 'budget',
160
+ anthropicPromptCaching: false,
161
+ impersonateClaudeCode: false,
162
+ maxOutputTokens: 32768,
163
+ hasSecret: false,
164
+ secretUpdatedAt: 0,
165
+ endpointDisclosureHost: '',
166
+ endpointDisclosureBaseUrl: '',
167
+ modelDiagnostics: {},
168
+ lastVerified: null
169
+ };
170
+ }
171
+
172
+ function getActiveProvider(catalog = {}) {
173
+ const normalized = normalizeCatalog(catalog);
174
+ return normalized.providers.find(provider => provider.id === normalized.activeProviderId)
175
+ || buildBuiltinProvider();
176
+ }
177
+
178
+ function buildRunSelection(catalog = {}) {
179
+ const active = getActiveProvider(catalog);
180
+ return {
181
+ providerId: active.id,
182
+ providerRevision: active.revision || 0
183
+ };
184
+ }
185
+
186
+ function normalizeWireApi(value, allowAuto) {
187
+ const normalized = normalizeText(value).toLowerCase();
188
+ if (normalized === 'responses' || normalized === 'chat' || normalized === 'anthropic') {
189
+ return normalized;
190
+ }
191
+ return allowAuto ? 'auto' : '';
192
+ }
193
+
194
+ function normalizeReasoningAdapter(value) {
195
+ const normalized = normalizeText(value).toLowerCase();
196
+ return ['auto', 'none', 'deepseek', 'anthropic', 'reasoning_effort', 'openrouter', 'enable_thinking', 'thinking', 'reasoning_split'].includes(normalized)
197
+ ? normalized
198
+ : 'auto';
199
+ }
200
+
201
+ function normalizeReasoningCapability(value) {
202
+ const normalized = normalizeText(value).toLowerCase();
203
+ return ['auto', 'none', 'toggle', 'effort'].includes(normalized) ? normalized : 'auto';
204
+ }
205
+
206
+ function normalizeUpstreamResponseMode(value, allowAuto) {
207
+ const normalized = normalizeText(value).toLowerCase();
208
+ if (normalized === 'streaming' || normalized === 'buffered' || (allowAuto && normalized === 'auto')) {
209
+ return normalized;
210
+ }
211
+ return allowAuto ? 'auto' : '';
212
+ }
213
+
214
+ function normalizeAuthMode(value) {
215
+ const normalized = normalizeText(value).toLowerCase();
216
+ return ['bearer', 'x-api-key', 'api-key', 'custom', 'none'].includes(normalized)
217
+ ? normalized
218
+ : 'bearer';
219
+ }
220
+
221
+ function normalizeRecord(value) {
222
+ return value && typeof value === 'object' && !Array.isArray(value) ? { ...value } : {};
223
+ }
224
+
225
+ function normalizeModelDiagnostics(value) {
226
+ if (!value || typeof value !== 'object' || Array.isArray(value)) {
227
+ return {};
228
+ }
229
+ const result = {};
230
+ for (const [rawModelId, rawDiagnostic] of Object.entries(value).slice(0, 32)) {
231
+ const modelId = normalizeText(rawModelId);
232
+ if (!modelId || !rawDiagnostic || typeof rawDiagnostic !== 'object') {
233
+ continue;
234
+ }
235
+ const status = normalizeText(rawDiagnostic.status).toLowerCase();
236
+ result[modelId] = {
237
+ modelId,
238
+ status: status === 'failed' ? 'failed' : 'tested',
239
+ at: normalizeInteger(rawDiagnostic.at),
240
+ wireApi: normalizeWireApi(rawDiagnostic.wireApi, false),
241
+ upstreamResponseMode: normalizeUpstreamResponseMode(rawDiagnostic.upstreamResponseMode, false),
242
+ durationMs: normalizeInteger(rawDiagnostic.durationMs),
243
+ errorCode: normalizeText(rawDiagnostic.errorCode)
244
+ };
245
+ }
246
+ return result;
247
+ }
248
+
249
+ function normalizeInputModalities(value) {
250
+ const values = Array.isArray(value) ? value : ['text'];
251
+ const result = Array.from(new Set(values.map(normalizeText).filter(item => item === 'text' || item === 'image')));
252
+ return result.includes('text') ? result : ['text', ...result];
253
+ }
254
+
255
+ function normalizeAnthropicThinkingMode(value) {
256
+ const normalized = normalizeText(value).toLowerCase();
257
+ return ['budget', 'adaptive', 'none'].includes(normalized) ? normalized : 'budget';
258
+ }
259
+
260
+ function normalizeText(value) {
261
+ return typeof value === 'string' ? value.trim() : '';
262
+ }
263
+
264
+ function normalizeInteger(value) {
265
+ const number = Number(value);
266
+ return Number.isFinite(number) && number >= 0 ? Math.floor(number) : 0;
267
+ }
268
+
269
+ function normalizeMaxOutputTokens(value) {
270
+ const number = normalizeInteger(value);
271
+ return !number || number === 8192 ? 32768 : number;
272
+ }
273
+
274
+ return {
275
+ BUILTIN_PROVIDER_ID,
276
+ buildBuiltinProvider,
277
+ buildEmptyDraft,
278
+ buildRunSelection,
279
+ getActiveProvider,
280
+ normalizeCatalog,
281
+ normalizeProvider
282
+ };
283
+ });
@@ -19,6 +19,7 @@
19
19
  locale: 'en',
20
20
  requireReviewing: true,
21
21
  autoOpen: true,
22
+ preloadProjectContext: true,
22
23
  loadCodexLocalSkills: true,
23
24
  loadCodexOverleafSkills: true,
24
25
  codexOverleafSkillEnabled: {},
@@ -34,7 +35,12 @@
34
35
  };
35
36
 
36
37
  const VALID_MODES = new Set(['ask', 'confirm', 'auto']);
37
- const VALID_REASONING = new Set(['low', 'medium', 'high', 'xhigh']);
38
+ // Keep the persisted/session-level contract aligned with the model picker
39
+ // and native provider bridge. Custom providers can explicitly disable
40
+ // reasoning (`none`) or expose the lightest Codex tier (`minimal`). Dropping
41
+ // either value here silently restores the global `high` default after the
42
+ // user has selected it in the composer.
43
+ const VALID_REASONING = new Set(['none', 'minimal', 'low', 'medium', 'high', 'xhigh']);
38
44
  const VALID_SPEED_TIERS = new Set(['standard', 'fast']);
39
45
  const VALID_LOCALES = new Set(['en', 'zh']);
40
46
  const VALID_EVENT_STATUSES = new Set(['info', 'running', 'completed', 'failed', 'warning', 'blocked', 'skipped', 'pending']);
@@ -63,7 +69,10 @@
63
69
  maxUndoRunsPerSession: 2,
64
70
  maxUndoBytesPerRun: 320 * 1024,
65
71
  targetBytes: 4 * 1024 * 1024,
66
- titleChars: 6000,
72
+ // Stream events carry accumulated assistant/reasoning text in `title`.
73
+ // Keep one provider-sized response intact; the 4 MiB state target below
74
+ // remains the aggregate history guard and prunes older events when needed.
75
+ titleChars: 128 * 1024,
67
76
  detailChars: 3000,
68
77
  reportDetailChars: 64000,
69
78
  historyChars: 1800,
@@ -945,6 +954,7 @@
945
954
  locale: normalizeLocale(source.locale),
946
955
  requireReviewing: active ? active.requireReviewing !== false : source.requireReviewing !== false,
947
956
  autoOpen: source.autoOpen !== false,
957
+ preloadProjectContext: source.preloadProjectContext !== false,
948
958
  loadCodexLocalSkills: source.loadCodexLocalSkills !== false,
949
959
  loadCodexOverleafSkills: source.loadCodexOverleafSkills !== false,
950
960
  codexOverleafSkillEnabled: normalizeCodexOverleafSkillEnabled(source.codexOverleafSkillEnabled),
@@ -26,7 +26,7 @@
26
26
  taskChars: 12000,
27
27
  historyTaskChars: 300,
28
28
  historyResultChars: 1800,
29
- eventTitleChars: 6000,
29
+ eventTitleChars: 128 * 1024,
30
30
  statusTextChars: 800,
31
31
  detailChars: 3000,
32
32
  reportDetailChars: 64000,