fix(zed): read legacy uncompressed json thread rows

Zed's DataType enum carries both zstd (the current save path) and json;
verified against crates/agent/src/db.rs, along with the exact TokenUsage
field names, the SerializedLanguageModel {provider, model} shape, and
RFC3339 updated_at serialization.
This commit is contained in:
AgentSeal 2026-07-02 05:46:59 +02:00
parent 1f45c1541b
commit a936e28595
2 changed files with 26 additions and 3 deletions

View file

@ -112,7 +112,9 @@ function parseThreads(db: SqliteDatabase, seenKeys: Set<string>): ParsedProvider
for (const row of rows) {
try {
if (!row.id || !row.data || row.data_type !== 'zstd') {
// Zed's DataType enum is "zstd" (current save path) or "json" (legacy
// uncompressed rows); anything else is unknown.
if (!row.id || !row.data || (row.data_type !== 'zstd' && row.data_type !== 'json')) {
if (row.data != null) skipped++
continue
}
@ -120,7 +122,10 @@ function parseThreads(db: SqliteDatabase, seenKeys: Set<string>): ParsedProvider
if (Number.isNaN(parsedAt.getTime())) continue
const timestamp = parsedAt.toISOString()
const thread = JSON.parse(zstdDecompress!(Buffer.from(row.data)).toString('utf-8')) as ThreadJson
const jsonText = row.data_type === 'zstd'
? zstdDecompress!(Buffer.from(row.data)).toString('utf-8')
: Buffer.from(row.data).toString('utf-8')
const thread = JSON.parse(jsonText) as ThreadJson
const model = thread.model?.model || 'unknown'
const userMessage = row.summary ?? ''

View file

@ -138,7 +138,7 @@ describe.skipIf(skipReason !== null)('zed provider (#480)', () => {
it('skips non-zstd rows and malformed blobs without dropping healthy threads', async () => {
const dbPath = buildDb((db) => {
insertThread(db, { id: 'bad-type', dataType: 'json', rawData: Buffer.from('{}') })
insertThread(db, { id: 'bad-type', dataType: 'protobuf', rawData: Buffer.from('{}') })
insertThread(db, { id: 'bad-blob', rawData: Buffer.from('not zstd at all') })
insertThread(db, {
id: 'good',
@ -154,6 +154,24 @@ describe.skipIf(skipReason !== null)('zed provider (#480)', () => {
expect(calls[0]!.sessionId).toBe('good')
})
it('reads legacy uncompressed json rows alongside zstd rows', async () => {
const dbPath = buildDb((db) => {
insertThread(db, {
id: 'legacy',
dataType: 'json',
rawData: Buffer.from(JSON.stringify({
model: { model: 'claude-sonnet-4-6' },
request_token_usage: { 'req-1': { input_tokens: 40, output_tokens: 8 } },
})),
})
})
const calls = await collectCalls(dbPath)
expect(calls.length).toBe(1)
expect(calls[0]!.inputTokens).toBe(40)
expect(calls[0]!.model).toBe('claude-sonnet-4-6')
})
it('dedupes across repeat parses via the shared seenKeys set', async () => {
const dbPath = buildDb((db) => {
insertThread(db, {