@gotcos/glasses-server 6.36.5 → 6.36.6
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/CHANGELOG.md +26 -0
- package/package.json +1 -1
- package/server/lib/agent-session-store.ts +69 -4
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,31 @@
|
|
|
1
1
|
## Unreleased
|
|
2
2
|
|
|
3
|
+
## 6.36.6
|
|
4
|
+
- **The session digest follows the thread instead of its opening.** Miles, from the
|
|
5
|
+
lens: "It's currently showing a legacy session that I had over a day ago... The
|
|
6
|
+
discussion should show the questions that we're asking and a summary of those most
|
|
7
|
+
recent things, not something that's the 'first' message." The whole budget now goes
|
|
8
|
+
to recency. `DIGEST_HEAD_TURNS` drops from 2 to 0 — a deliberate reversal of the
|
|
9
|
+
earlier rule that reserved the opening ask because it "frames everything after it".
|
|
10
|
+
The opening is not lost: `first_prompt` still carries it in full.
|
|
11
|
+
- **Harness-injected rows no longer render as things you asked.** A slash-command body
|
|
12
|
+
and a compaction preamble are both written as USER rows, so both appeared in the
|
|
13
|
+
DISCUSSION list. Filtered on the STRUCTURAL flags Claude already sets — `isMeta` and
|
|
14
|
+
`isCompactSummary` — not on a markdown heuristic that could misfire on a real paste.
|
|
15
|
+
The compaction preamble is also filtered by text as a fallback for providers that
|
|
16
|
+
emit no flag, and that filter reaches titles and the search index too: the preamble
|
|
17
|
+
is byte-identical across every compacted session, so as a title or a search hit it
|
|
18
|
+
distinguishes nothing.
|
|
19
|
+
- **On a truncated read the head window no longer feeds the recency list.** The head
|
|
20
|
+
window IS the session opening, and on a large session the 60-turn window never fills,
|
|
21
|
+
so those turns survived at the top of the digest indefinitely. Measured on a real
|
|
22
|
+
94 MiB session: both leading bullets were head-window turns from the previous day.
|
|
23
|
+
A whole-file read is untouched — it yields `tail: true` for every line.
|
|
24
|
+
- Verified by parsing real transcripts, not fixtures: the 94 MiB session now leads with
|
|
25
|
+
the two most recent asks, and an ordinary 2.7 MiB session renders nine recent turns
|
|
26
|
+
in reading order.
|
|
27
|
+
|
|
28
|
+
|
|
3
29
|
## 6.36.5
|
|
4
30
|
- **A speaker merge now reaches the meetings, not just the voice store.**
|
|
5
31
|
`merge-profiles` folded two profiles together and relabelled the calibration log,
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@gotcos/glasses-server",
|
|
3
|
-
"version": "6.36.
|
|
3
|
+
"version": "6.36.6",
|
|
4
4
|
"description": "COS Glasses \u2014 self-hosted AI heads-up-display server for Even G2 smart glasses, powered by Claude Code, Codex, or Cursor Agent CLI",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"bin": {
|
|
@@ -103,6 +103,22 @@ export function isKeepWarmSessionTitle(title: string): boolean {
|
|
|
103
103
|
return t.startsWith('this is an automated local readiness check')
|
|
104
104
|
}
|
|
105
105
|
|
|
106
|
+
/**
|
|
107
|
+
* The compaction preamble, which the harness writes as a USER turn.
|
|
108
|
+
*
|
|
109
|
+
* Miles's 2026-08-17 screenshot had this sitting in the DISCUSSION list as though he
|
|
110
|
+
* had asked it: "This session is being continued from a previous conversation… Summary:
|
|
111
|
+
* ## 1. Primary Request and Intent". It is scaffolding, and it lands in the digest at
|
|
112
|
+
* full length because it IS recent -- compaction happens mid-session -- so recency
|
|
113
|
+
* ordering alone does not remove it.
|
|
114
|
+
*
|
|
115
|
+
* Measured across the 25 most recently written transcripts on this machine: 29
|
|
116
|
+
* occurrences, exactly ONE distinct opening. Anchored to that opening rather than to a
|
|
117
|
+
* loose "continued from" match, so a human sentence about continuing a conversation is
|
|
118
|
+
* not mistaken for it.
|
|
119
|
+
*/
|
|
120
|
+
const COMPACTION_PREAMBLE = /^this session is being continued from a previous conversation/i
|
|
121
|
+
|
|
106
122
|
export function isWrapperPrompt(text: string): boolean {
|
|
107
123
|
const trimmed = text.trim()
|
|
108
124
|
return trimmed.startsWith('<')
|
|
@@ -110,6 +126,10 @@ export function isWrapperPrompt(text: string): boolean {
|
|
|
110
126
|
|| trimmed.startsWith('You are an agent')
|
|
111
127
|
|| trimmed.startsWith('You are QA Agent')
|
|
112
128
|
|| trimmed.startsWith('Message Type:')
|
|
129
|
+
// Filtered HERE rather than only in the digest, so it also stops titling a session
|
|
130
|
+
// and stops being indexed for search. It is byte-identical across every compacted
|
|
131
|
+
// session, so as a title or a search hit it distinguishes nothing.
|
|
132
|
+
|| COMPACTION_PREAMBLE.test(trimmed)
|
|
113
133
|
}
|
|
114
134
|
|
|
115
135
|
export function firstLineTitle(text: string): string {
|
|
@@ -249,7 +269,27 @@ export const DISCUSSION_DIGEST_MAX = 2000
|
|
|
249
269
|
const DIGEST_TURN_MAX = 220
|
|
250
270
|
|
|
251
271
|
/** Turns kept from the START. The opening ask frames everything after it. */
|
|
252
|
-
|
|
272
|
+
/**
|
|
273
|
+
* User turns reserved from the START of the session before recency gets the budget.
|
|
274
|
+
*
|
|
275
|
+
* ZERO, AND THAT IS A REVERSAL. This was 2, on the reasoning that the opening ask
|
|
276
|
+
* "frames everything after it" -- see the head-first block in composeDiscussionDigest,
|
|
277
|
+
* which was itself a fix for a digest that spent everything on the tail.
|
|
278
|
+
*
|
|
279
|
+
* Miles overruled it from hardware, 2026-08-17, looking at a digest whose first two
|
|
280
|
+
* bullets were a question from the previous day and a compaction preamble: "It needs to
|
|
281
|
+
* refresh to the most recent response inside of the thread. The discussion should show
|
|
282
|
+
* the questions that we're asking and a summary of those most recent things, not
|
|
283
|
+
* something that's the 'first' message."
|
|
284
|
+
*
|
|
285
|
+
* The opening ask is NOT lost -- it is still carried, in full, in `first_prompt`, which
|
|
286
|
+
* the digest and the row label both fall back to. What changes is that it stops
|
|
287
|
+
* occupying the two most valuable slots in a list about what is happening NOW.
|
|
288
|
+
*
|
|
289
|
+
* Left as a constant rather than deleting the head path: this is a judgement call about
|
|
290
|
+
* emphasis, and one number is the whole reversal if Miles wants some framing back.
|
|
291
|
+
*/
|
|
292
|
+
const DIGEST_HEAD_TURNS = 0
|
|
253
293
|
|
|
254
294
|
/** Recent turns retained while streaming. Comfortably more than 2000 chars can
|
|
255
295
|
* render (~20-25 at typical length), so the budget and not the buffer decides
|
|
@@ -1341,7 +1381,32 @@ export async function parseAgentSession(
|
|
|
1341
1381
|
// reports what was actually dropped rather than what this buffer happens to hold.
|
|
1342
1382
|
const digestHead: string[] = []
|
|
1343
1383
|
const digestRecent: string[] = []
|
|
1344
|
-
|
|
1384
|
+
/**
|
|
1385
|
+
* Add a user turn to the recency digest -- or decline to.
|
|
1386
|
+
*
|
|
1387
|
+
* TWO DECLINES, both found by parsing Miles's own 94 MiB session rather than by
|
|
1388
|
+
* reasoning about the code.
|
|
1389
|
+
*
|
|
1390
|
+
* `injected`: STRUCTURAL, not a heuristic. Claude marks a slash-command body with
|
|
1391
|
+
* `isMeta: true` and a compaction preamble with `isCompactSummary: true`. Both are
|
|
1392
|
+
* written as USER rows, so both rendered in the digest as things Miles had asked --
|
|
1393
|
+
* his screenshot led with "This session is being continued from a previous
|
|
1394
|
+
* conversation… Summary: ## 1. Primary Request and Intent". Neither is an ask, and
|
|
1395
|
+
* both are recent, so recency ordering alone leaves them exactly where they were.
|
|
1396
|
+
*
|
|
1397
|
+
* `fromTail` on a TRUNCATED read: the head window IS the session opening. Feeding it
|
|
1398
|
+
* into a recency list is the very thing Miles objected to -- "not something that's
|
|
1399
|
+
* the 'first' message" -- and on a large session the 60-turn window never fills, so
|
|
1400
|
+
* those opening turns survive to the top of the digest forever. Measured on his
|
|
1401
|
+
* session: the two leading bullets were both head-window turns from the previous day.
|
|
1402
|
+
* The head is still read and still published, as `first_prompt`.
|
|
1403
|
+
*
|
|
1404
|
+
* A whole-file read yields `tail: true` for every line, so a normal session is
|
|
1405
|
+
* unaffected -- this narrows only the partial read.
|
|
1406
|
+
*/
|
|
1407
|
+
const collectTurn = (text: string, fromTail = true, injected = false): void => {
|
|
1408
|
+
if (injected) return
|
|
1409
|
+
if (truncated && !fromTail) return
|
|
1345
1410
|
// Reuse the wrapper filter the rest of this module already trusts. Without it the
|
|
1346
1411
|
// opening turns of a slash-command session render as
|
|
1347
1412
|
// "<command-message>cos-glasses</command-message>…" — scaffolding, not the ask,
|
|
@@ -1413,7 +1478,7 @@ export async function parseAgentSession(
|
|
|
1413
1478
|
}
|
|
1414
1479
|
if (obj.type === 'user') {
|
|
1415
1480
|
userCount += 1
|
|
1416
|
-
collectTurn(text)
|
|
1481
|
+
collectTurn(text, tail, obj.isMeta === true || obj.isCompactSummary === true)
|
|
1417
1482
|
if (!firstPrompt) firstPrompt = firstLineTitle(text)
|
|
1418
1483
|
if (!title) title = firstLineTitle(text)
|
|
1419
1484
|
} else {
|
|
@@ -1459,7 +1524,7 @@ export async function parseAgentSession(
|
|
|
1459
1524
|
if (obj.role === 'user') {
|
|
1460
1525
|
userCount += 1
|
|
1461
1526
|
const query = cursorUserTitle(text, true) ?? cursorUserTitle(text, false)
|
|
1462
|
-
collectTurn(query ?? text)
|
|
1527
|
+
collectTurn(query ?? text, tail)
|
|
1463
1528
|
if (query) {
|
|
1464
1529
|
title = query
|
|
1465
1530
|
if (!firstPrompt) firstPrompt = query
|