feat(id): brand PartID through Drizzle and Zod schemas (#16966)

This commit is contained in:
Kit Langton
2026-03-11 19:40:50 -04:00
committed by GitHub
parent d26c6f80e1
commit 090f636354
21 changed files with 102 additions and 97 deletions

View File

@@ -1,12 +1,12 @@
import { test, expect, describe } from "bun:test"
import { extractResponseText, formatPromptTooLargeError } from "../../src/cli/cmd/github"
import type { MessageV2 } from "../../src/session/message-v2"
import { SessionID, MessageID } from "../../src/session/schema"
import { SessionID, MessageID, PartID } from "../../src/session/schema"
// Helper to create minimal valid parts
function createTextPart(text: string): MessageV2.Part {
return {
id: "1",
id: PartID.ascending(),
sessionID: SessionID.make("s"),
messageID: MessageID.make("m"),
type: "text" as const,
@@ -16,7 +16,7 @@ function createTextPart(text: string): MessageV2.Part {
function createReasoningPart(text: string): MessageV2.Part {
return {
id: "1",
id: PartID.ascending(),
sessionID: SessionID.make("s"),
messageID: MessageID.make("m"),
type: "reasoning" as const,
@@ -28,7 +28,7 @@ function createReasoningPart(text: string): MessageV2.Part {
function createToolPart(tool: string, title: string, status: "completed" | "running" = "completed"): MessageV2.Part {
if (status === "completed") {
return {
id: "1",
id: PartID.ascending(),
sessionID: SessionID.make("s"),
messageID: MessageID.make("m"),
type: "tool" as const,
@@ -45,7 +45,7 @@ function createToolPart(tool: string, title: string, status: "completed" | "runn
}
}
return {
id: "1",
id: PartID.ascending(),
sessionID: SessionID.make("s"),
messageID: MessageID.make("m"),
type: "tool" as const,
@@ -61,7 +61,7 @@ function createToolPart(tool: string, title: string, status: "completed" | "runn
function createStepStartPart(): MessageV2.Part {
return {
id: "1",
id: PartID.ascending(),
sessionID: SessionID.make("s"),
messageID: MessageID.make("m"),
type: "step-start" as const,
@@ -70,7 +70,7 @@ function createStepStartPart(): MessageV2.Part {
function createStepFinishPart(): MessageV2.Part {
return {
id: "1",
id: PartID.ascending(),
sessionID: SessionID.make("s"),
messageID: MessageID.make("m"),
type: "step-finish" as const,

View File

@@ -2,7 +2,7 @@ import { describe, expect, test } from "bun:test"
import { APICallError } from "ai"
import { MessageV2 } from "../../src/session/message-v2"
import type { Provider } from "../../src/provider/provider"
import { SessionID, MessageID } from "../../src/session/schema"
import { SessionID, MessageID, PartID } from "../../src/session/schema"
const sessionID = SessionID.make("session")
const model: Provider.Model = {
@@ -98,7 +98,7 @@ function assistantInfo(
function basePart(messageID: string, id: string) {
return {
id,
id: PartID.make(id),
sessionID,
messageID: MessageID.make(messageID),
}

View File

@@ -6,8 +6,7 @@ import { SessionCompaction } from "../../src/session/compaction"
import { MessageV2 } from "../../src/session/message-v2"
import { Log } from "../../src/util/log"
import { Instance } from "../../src/project/instance"
import { Identifier } from "../../src/id/id"
import { MessageID } from "../../src/session/schema"
import { MessageID, PartID } from "../../src/session/schema"
import { tmpdir } from "../fixture/fixture"
const projectRoot = path.join(__dirname, "../..")
@@ -40,7 +39,7 @@ describe("revert + compact workflow", () => {
// Add a text part to the user message
await Session.updatePart({
id: Identifier.ascending("part"),
id: PartID.ascending(),
messageID: userMsg1.id,
sessionID,
type: "text",
@@ -77,7 +76,7 @@ describe("revert + compact workflow", () => {
// Add a text part to the assistant message
await Session.updatePart({
id: Identifier.ascending("part"),
id: PartID.ascending(),
messageID: assistantMsg1.id,
sessionID,
type: "text",
@@ -100,7 +99,7 @@ describe("revert + compact workflow", () => {
})
await Session.updatePart({
id: Identifier.ascending("part"),
id: PartID.ascending(),
messageID: userMsg2.id,
sessionID,
type: "text",
@@ -136,7 +135,7 @@ describe("revert + compact workflow", () => {
await Session.updateMessage(assistantMsg2)
await Session.updatePart({
id: Identifier.ascending("part"),
id: PartID.ascending(),
messageID: assistantMsg2.id,
sessionID,
type: "text",
@@ -215,7 +214,7 @@ describe("revert + compact workflow", () => {
})
await Session.updatePart({
id: Identifier.ascending("part"),
id: PartID.ascending(),
messageID: userMsg.id,
sessionID,
type: "text",
@@ -250,7 +249,7 @@ describe("revert + compact workflow", () => {
await Session.updateMessage(assistantMsg)
await Session.updatePart({
id: Identifier.ascending("part"),
id: PartID.ascending(),
messageID: assistantMsg.id,
sessionID,
type: "text",

View File

@@ -5,8 +5,7 @@ import { Bus } from "../../src/bus"
import { Log } from "../../src/util/log"
import { Instance } from "../../src/project/instance"
import { MessageV2 } from "../../src/session/message-v2"
import { Identifier } from "../../src/id/id"
import { MessageID } from "../../src/session/schema"
import { MessageID, PartID } from "../../src/session/schema"
const projectRoot = path.join(__dirname, "../..")
Log.init({ print: false })
@@ -108,7 +107,7 @@ describe("step-finish token propagation via Bus event", () => {
}
const partInput = {
id: Identifier.ascending("part"),
id: PartID.ascending(),
messageID,
sessionID: session.id,
type: "step-finish" as const,

View File

@@ -11,7 +11,7 @@ import { ProjectTable } from "../../src/project/project.sql"
import { ProjectID } from "../../src/project/schema"
import { SessionTable, MessageTable, PartTable, TodoTable, PermissionTable } from "../../src/session/session.sql"
import { SessionShareTable } from "../../src/share/share.sql"
import { SessionID, MessageID } from "../../src/session/schema"
import { SessionID, MessageID, PartID } from "../../src/session/schema"
// Test fixtures
const fixtures = {
@@ -259,7 +259,7 @@ describe("JSON to SQLite migration", () => {
const parts = db.select().from(PartTable).all()
expect(parts.length).toBe(1)
expect(parts[0].id).toBe("prt_testabc123")
expect(parts[0].id).toBe(PartID.make("prt_testabc123"))
})
test("migrates legacy parts without ids in body", async () => {
@@ -302,7 +302,7 @@ describe("JSON to SQLite migration", () => {
const parts = db.select().from(PartTable).all()
expect(parts.length).toBe(1)
expect(parts[0].id).toBe("prt_testabc123")
expect(parts[0].id).toBe(PartID.make("prt_testabc123"))
expect(parts[0].message_id).toBe(MessageID.make("msg_test789ghi"))
expect(parts[0].session_id).toBe(SessionID.make("ses_test456def"))
expect(parts[0].data).not.toHaveProperty("id")
@@ -374,7 +374,7 @@ describe("JSON to SQLite migration", () => {
const db = drizzle({ client: sqlite })
const parts = db.select().from(PartTable).all()
expect(parts.length).toBe(1)
expect(parts[0].id).toBe("prt_from_filename") // Uses filename, not JSON id
expect(parts[0].id).toBe(PartID.make("prt_from_filename")) // Uses filename, not JSON id
expect(parts[0].message_id).toBe(MessageID.make("msg_realmsgid")) // Uses parent dir, not JSON messageID
})