mirror of
https://gitea.toothfairyai.com/ToothFairyAI/tf_code.git
synced 2026-03-30 05:43:55 +00:00
- Rename packages/opencode → packages/tfcode (directory only) - Rename bin/opencode → bin/tfcode (CLI binary) - Rename .opencode → .tfcode (config directory) - Update package.json name and bin field - Update config directory path references (.tfcode) - Keep internal code references as 'opencode' for easy upstream sync - Keep @opencode-ai/* workspace package names This minimal branding approach allows clean merges from upstream opencode repository while providing tfcode branding for users.
116 lines
3.7 KiB
TypeScript
116 lines
3.7 KiB
TypeScript
import { describe, expect, test } from "bun:test"
|
|
import path from "path"
|
|
import { Instance } from "../../src/project/instance"
|
|
import { Session } from "../../src/session"
|
|
import { MessageV2 } from "../../src/session/message-v2"
|
|
import { MessageID, PartID, type SessionID } from "../../src/session/schema"
|
|
import { Log } from "../../src/util/log"
|
|
|
|
const root = path.join(__dirname, "../..")
|
|
Log.init({ print: false })
|
|
|
|
async function fill(sessionID: SessionID, count: number, time = (i: number) => Date.now() + i) {
|
|
const ids = [] as MessageID[]
|
|
for (let i = 0; i < count; i++) {
|
|
const id = MessageID.ascending()
|
|
ids.push(id)
|
|
await Session.updateMessage({
|
|
id,
|
|
sessionID,
|
|
role: "user",
|
|
time: { created: time(i) },
|
|
agent: "test",
|
|
model: { providerID: "test", modelID: "test" },
|
|
tools: {},
|
|
mode: "",
|
|
} as unknown as MessageV2.Info)
|
|
await Session.updatePart({
|
|
id: PartID.ascending(),
|
|
sessionID,
|
|
messageID: id,
|
|
type: "text",
|
|
text: `m${i}`,
|
|
})
|
|
}
|
|
return ids
|
|
}
|
|
|
|
describe("session message pagination", () => {
|
|
test("pages backward with opaque cursors", async () => {
|
|
await Instance.provide({
|
|
directory: root,
|
|
fn: async () => {
|
|
const session = await Session.create({})
|
|
const ids = await fill(session.id, 6)
|
|
|
|
const a = await MessageV2.page({ sessionID: session.id, limit: 2 })
|
|
expect(a.items.map((item) => item.info.id)).toEqual(ids.slice(-2))
|
|
expect(a.items.every((item) => item.parts.length === 1)).toBe(true)
|
|
expect(a.more).toBe(true)
|
|
expect(a.cursor).toBeTruthy()
|
|
|
|
const b = await MessageV2.page({ sessionID: session.id, limit: 2, before: a.cursor! })
|
|
expect(b.items.map((item) => item.info.id)).toEqual(ids.slice(-4, -2))
|
|
expect(b.more).toBe(true)
|
|
expect(b.cursor).toBeTruthy()
|
|
|
|
const c = await MessageV2.page({ sessionID: session.id, limit: 2, before: b.cursor! })
|
|
expect(c.items.map((item) => item.info.id)).toEqual(ids.slice(0, 2))
|
|
expect(c.more).toBe(false)
|
|
expect(c.cursor).toBeUndefined()
|
|
|
|
await Session.remove(session.id)
|
|
},
|
|
})
|
|
})
|
|
|
|
test("keeps stream order newest first", async () => {
|
|
await Instance.provide({
|
|
directory: root,
|
|
fn: async () => {
|
|
const session = await Session.create({})
|
|
const ids = await fill(session.id, 5)
|
|
|
|
const items = await Array.fromAsync(MessageV2.stream(session.id))
|
|
expect(items.map((item) => item.info.id)).toEqual(ids.slice().reverse())
|
|
|
|
await Session.remove(session.id)
|
|
},
|
|
})
|
|
})
|
|
|
|
test("accepts cursors generated from fractional timestamps", async () => {
|
|
await Instance.provide({
|
|
directory: root,
|
|
fn: async () => {
|
|
const session = await Session.create({})
|
|
const ids = await fill(session.id, 4, (i) => 1000.5 + i)
|
|
|
|
const a = await MessageV2.page({ sessionID: session.id, limit: 2 })
|
|
const b = await MessageV2.page({ sessionID: session.id, limit: 2, before: a.cursor! })
|
|
|
|
expect(a.items.map((item) => item.info.id)).toEqual(ids.slice(-2))
|
|
expect(b.items.map((item) => item.info.id)).toEqual(ids.slice(0, 2))
|
|
|
|
await Session.remove(session.id)
|
|
},
|
|
})
|
|
})
|
|
|
|
test("scopes get by session id", async () => {
|
|
await Instance.provide({
|
|
directory: root,
|
|
fn: async () => {
|
|
const a = await Session.create({})
|
|
const b = await Session.create({})
|
|
const [id] = await fill(a.id, 1)
|
|
|
|
await expect(MessageV2.get({ sessionID: b.id, messageID: id })).rejects.toMatchObject({ name: "NotFoundError" })
|
|
|
|
await Session.remove(a.id)
|
|
await Session.remove(b.id)
|
|
},
|
|
})
|
|
})
|
|
})
|