chore: Fix seed assistant threads so the assistant page can list them (no-changelog) (#37863)

Co-authored-by: Claude Fable 5.1 <[email protected]>
This commit is contained in:
Svetoslav Dekov
2026-09-08 09:24:24 +00:00
committed by GitHub
co-authored by Claude Fable 5.1
parent bbc8e83e5d
commit 5cfae1ce62
2 changed files with 55 additions and 9 deletions
+21 -9
View File
@@ -298,12 +298,20 @@ function main() {
// workflow, so a "what was I working on?" probe has something to find.
const threadId = uuid();
const threadAt = NOW - Math.floor(random() * DAYS * 86400e3);
// `resourceId` is the owning user: the assistant page lists threads by it, so a
// workflow id here makes the thread exist but never show. The workflow goes in
// `sourceContext`, where the runtime also puts it.
insThread.run(
threadId,
wf.id,
user.id,
project.id,
`Working on ${short}`,
`{${THREAD_MARKER}}`,
JSON.stringify({
seeded: true,
source: 'assistant_page',
origin: 'internal',
sourceContext: { workflowId: wf.id },
}),
iso(threadAt),
iso(threadAt + 600e3),
);
@@ -329,16 +337,20 @@ function main() {
`Added a Data Table insert named "Record Run" at the end of ${short}, writing to \`automation_runs\`, matching the other workflows here.`,
],
];
for (const [role, content] of turns) {
// `content` holds the whole agent message as JSON, the way the runtime stores it.
// A plain string is dropped on read, so the thread would open empty.
for (const [i, [role, text]] of turns.entries()) {
const messageId = uuid();
const createdAt = iso(threadAt + i * 30e3);
insMessage.run(
uuid(),
messageId,
threadId,
content,
JSON.stringify({ id: messageId, role, content: [{ type: 'text', text }], createdAt }),
role,
'message',
wf.id,
iso(threadAt),
iso(threadAt),
null,
user.id,
createdAt,
createdAt,
);
msgCount++;
}
@@ -192,6 +192,40 @@ describe('seedHistory cleanup', () => {
assert.ok(c.seededActivity > 0, 'activity written');
});
// The assistant page lists threads by `resourceId = user id` and drops any message
// whose `content` is not an agent-message JSON object, so both must match the runtime.
it('writes threads and messages the assistant page can read', () => {
const dbFile = fixture();
run(dbFile);
const db = new DatabaseSync(dbFile, { readOnly: true });
const threads = db
.prepare(
`SELECT resourceId FROM instance_ai_threads WHERE metadata LIKE '%"seeded":true%' AND projectId = 'p-seed'`,
)
.all();
assert.ok(threads.length > 0);
assert.ok(
threads.every((t) => t.resourceId === 'u1'),
'threads owned by the first user',
);
const messages = db
.prepare(
`SELECT m.content, m.resourceId, m.type FROM instance_ai_messages m
JOIN instance_ai_threads t ON t.id = m.threadId
WHERE t.metadata LIKE '%"seeded":true%' AND t.projectId = 'p-seed'`,
)
.all();
assert.ok(messages.length > 0);
for (const m of messages) {
assert.equal(m.resourceId, 'u1');
assert.equal(m.type, null);
const parsed = JSON.parse(m.content);
assert.ok(['user', 'assistant'].includes(parsed.role));
assert.equal(parsed.content[0].type, 'text');
}
db.close();
});
it('leaves rows it did not create alone', () => {
const dbFile = fixture();
run(dbFile);