@gotcos/glasses-server 6.53.4 → 6.55.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.
@@ -194,7 +194,9 @@ function safeProofError(result: ProcessResult): string {
194
194
  return 'provider returned no valid proof response'
195
195
  }
196
196
 
197
- const QUOTA_RE = /usage limit|hit your (?:usage |session )?limit|session limit|rate.?limit|too many requests|\b429\b|\bquota\b|resets? (?:at|in) |over capacity|overloaded|\b529\b|plan limit/i
197
+ /** A provider's own words for a spent session, usage, rate or capacity limit. Also the lens
198
+ * gist's (lens-gist-engines.ts), so both read a limit the same way. */
199
+ export const PROVIDER_QUOTA_RE = /usage[ _]limit|hit your (?:usage |session )?limit|session limit|rate.?limit|too many requests|\b429\b|\bquota\b|resets? (?:at|in) |over capacity|overloaded|\b529\b|plan limit/i
198
200
  const AUTH_RE = /not logged in|please (?:log ?in|sign in)|invalid api key|authentication|unauthori[sz]ed|\b401\b|\b403\b|login required|token (?:has )?expired|no credentials/i
199
201
  const OVERFLOW_RE = /prompt is too long|context window|too many tokens|exceeds the (?:model|context)/i
200
202
  const MISSING_RE = /ENOENT|command not found|no such file/i
@@ -209,7 +211,7 @@ export function classifyProofFailure(result: ProcessResult, answer: string, expe
209
211
  const haystack = `${result.stderr}\n${result.stdout}`.slice(0, 40_000)
210
212
  if (result.code === null && MISSING_RE.test(haystack)) return 'provider_missing'
211
213
  if (OVERFLOW_RE.test(haystack)) return 'provider_context_overflow'
212
- if (QUOTA_RE.test(haystack)) return 'provider_quota'
214
+ if (PROVIDER_QUOTA_RE.test(haystack)) return 'provider_quota'
213
215
  if (AUTH_RE.test(haystack)) return 'provider_auth'
214
216
  if (result.code === 0) return answer === expected ? 'provider_failed' : 'provider_bad_answer'
215
217
  return 'provider_failed'
@@ -22,6 +22,7 @@ import {
22
22
  } from '../lib/whisper-local.js'
23
23
  import { getOpenAIWhisperBudgetState } from '../lib/openai-whisper-budget.js'
24
24
  import { getMeetingSummaryBudgetState } from '../lib/meeting-summary-budget.js'
25
+ import { lensGistPublicHealth } from '../lib/lens-gist.js'
25
26
  import { meetingSummaryLLMEnabled } from '../lib/meeting-summary.js'
26
27
  import { getKeyStatus } from '../lib/openai-key.js'
27
28
  import {
@@ -410,6 +411,8 @@ healthRouter.get('/health', async (_req, res) => {
410
411
  whisper_health,
411
412
  openai_whisper_budget,
412
413
  meeting_summary,
414
+ // 6.54.0: the lens gist engine (lib/lens-gist.ts); detail on /api/lens-gist/config.
415
+ lens_gist: lensGistPublicHealth(),
413
416
  tts_local,
414
417
  codex_models,
415
418
  cursor_models,
@@ -0,0 +1,58 @@
1
+ import { Router } from 'express'
2
+ import {
3
+ LensGistInputError,
4
+ getLensGist,
5
+ lensGistHealth,
6
+ listLensGistEngines,
7
+ normalizeLensGistInput,
8
+ saveLensGistConfig,
9
+ } from '../lib/lens-gist.js'
10
+ import { maintenanceAdmissionsOpen } from '../lib/maintenance-lifecycle.js'
11
+ import { errMsg } from '../lib/utils.js'
12
+
13
+ // Server 6.54.0. The phone asks for the three-line card behind the G2 prompt box
14
+ // (lib/lens-gist.ts). Every answer the server gives is a 200 with a `status`, so the
15
+ // phone never reads "the server answered no" as "the server is unreachable" (gotchas:
16
+ // an HTTP status means the server ANSWERED). Only a malformed request is a 400.
17
+ export const lensGistRouter = Router()
18
+
19
+ lensGistRouter.post('/lens-gist', async (req, res) => {
20
+ let input
21
+ try {
22
+ input = normalizeLensGistInput(req.body)
23
+ } catch (err) {
24
+ res.status(err instanceof LensGistInputError ? err.status : 400).json({ error: errMsg(err) })
25
+ return
26
+ }
27
+ // Outside the request lease (index.ts lifecycleOwned): a drain for an update or restart
28
+ // closes admissions, and a gist is the first thing to give way.
29
+ if (!maintenanceAdmissionsOpen()) {
30
+ res.json({ status: 'unavailable', reason: 'maintenance' })
31
+ return
32
+ }
33
+ // No abort on disconnect: the phone asks ahead of the hold and may not wait, and the
34
+ // answer is cached for when it asks again.
35
+ try {
36
+ res.json(await getLensGist(input))
37
+ } catch (err) {
38
+ res.status(500).json({ error: errMsg(err) })
39
+ }
40
+ })
41
+
42
+ lensGistRouter.get('/lens-gist/config', async (_req, res) => {
43
+ try {
44
+ res.json({ ...lensGistHealth(), engines: await listLensGistEngines() })
45
+ } catch (err) {
46
+ res.status(500).json({ error: errMsg(err) })
47
+ }
48
+ })
49
+
50
+ lensGistRouter.put('/lens-gist/config', (req, res) => {
51
+ try {
52
+ const saved = saveLensGistConfig(req.body ?? {})
53
+ const overridden = !!process.env.COS_LENS_GIST_ENGINE?.trim()
54
+ res.json({ saved: true, effective: saved, ...(overridden ? { overriddenByEnv: 'COS_LENS_GIST_ENGINE' } : {}) })
55
+ } catch (err) {
56
+ res.status(err instanceof LensGistInputError ? err.status : 500).json({ error: errMsg(err) })
57
+ }
58
+ })