Repository navigation
Conversation
2719644 to
e149278
Compare
|
Filed the underlying report as #593. Rebased onto current main (the adapter gained |
|
Root cause confirmed. We hit this on 0.0.21 (Postgres, Bun 1.4.2): AI chat messages are stored as One caveat with this approach: stringifying all object params breaks ${{ theme: 'dark' }} // jsonb_typeof = object, ->>'theme' = 'dark'
${JSON.stringify({ theme: 'dark' })} // jsonb_typeof = string, ->>'theme' = NULLReads still work (
|
On Postgres `ai_messages.content_json` is `text`, and Bun SQL binds a plain array to a text parameter via String(), storing '[object Object]'. Replaying that history yields empty user content and provider calls fail (Anthropic: 400 "user messages must have non-empty content"). JSON.stringify the content at the insert. SQLite passes strings through unchanged, and reads on both dialects JSON.parse `_json` strings, so behavior there is identical. Kept narrow on purpose: stringifying every object param in the PG adapter would turn values bound to jsonb columns into JSON string scalars and break jsonField() queries. Fixes CoreBunch#593. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
e149278 to
2a7a6ef
Compare
|
Thanks @qu4ntom, good catch on |
Fixes #593.
Problem
On Postgres,
ai_messages.content_jsonis atextcolumn. Bun SQL binds a plain array to atextparameter viaString(), so every AI message is stored as the literal'[object Object]'. On replay the row fails schema validation, history comes back with empty content, and the provider call fails (Anthropic:400 user messages must have non-empty content).Fix
JSON.stringify(input.content)at the single insert inserver/ai/conversations/store.ts.normalizePostgresRowalreadyJSON.parses string-valued*_jsoncolumns on read.toBindablepasses strings through unchanged, so what gets stored is byte-for-byte the same as before.Why narrow (revised)
The first version of this PR serialized every object param in the Postgres adapter. As @qu4ntom pointed out, that breaks
jsonbcolumns: Bun binds objects tojsonbcorrectly today, and a pre-stringified value would be stored as a JSON string scalar, sojsonField()queries (data-row filters, plugins) would stop matching new rows.content_jsonis the onlytextJSON column inmigrations-pg.ts, so the fix belongs at that call site.Not included
'[object Object]'aren't recoverable. They read back as empty blocks, which the read path already handles. Migrating the column tojsonbcould be a follow-up if you'd prefer that over the call-site fix.Verification
bun test src/__tests__/ai/(conversation / tool-result / image round-trip tests): green🤖 Generated with Claude Code