fix: address Cubic round-3 P2/P3 issues
- Encode path segments with encodeURIComponent in HTTP API URLs to prevent broken requests when IDs contain special characters - Remove unused readMessagesFromSDK from messages-reader.ts (production callers use local implementations; dead code)
This commit is contained in:
parent
5f97a58019
commit
d7b38d7c34
@ -1,7 +1,6 @@
|
|||||||
export { generatePartId } from "./storage/part-id"
|
export { generatePartId } from "./storage/part-id"
|
||||||
export { getMessageDir } from "./storage/message-dir"
|
export { getMessageDir } from "./storage/message-dir"
|
||||||
export { readMessages } from "./storage/messages-reader"
|
export { readMessages } from "./storage/messages-reader"
|
||||||
export { readMessagesFromSDK } from "./storage/messages-reader"
|
|
||||||
export { readParts } from "./storage/parts-reader"
|
export { readParts } from "./storage/parts-reader"
|
||||||
export { readPartsFromSDK } from "./storage/parts-reader"
|
export { readPartsFromSDK } from "./storage/parts-reader"
|
||||||
export { hasContent, messageHasContent } from "./storage/part-content"
|
export { hasContent, messageHasContent } from "./storage/part-content"
|
||||||
|
|||||||
@ -1,39 +1,9 @@
|
|||||||
import { existsSync, readdirSync, readFileSync } from "node:fs"
|
import { existsSync, readdirSync, readFileSync } from "node:fs"
|
||||||
import { join } from "node:path"
|
import { join } from "node:path"
|
||||||
import type { PluginInput } from "@opencode-ai/plugin"
|
|
||||||
import type { StoredMessageMeta } from "../types"
|
import type { StoredMessageMeta } from "../types"
|
||||||
import { getMessageDir } from "./message-dir"
|
import { getMessageDir } from "./message-dir"
|
||||||
import { isSqliteBackend } from "../../../shared"
|
import { isSqliteBackend } from "../../../shared"
|
||||||
|
|
||||||
type OpencodeClient = PluginInput["client"]
|
|
||||||
|
|
||||||
function isRecord(value: unknown): value is Record<string, unknown> {
|
|
||||||
return typeof value === "object" && value !== null
|
|
||||||
}
|
|
||||||
|
|
||||||
function normalizeSDKMessage(
|
|
||||||
sessionID: string,
|
|
||||||
value: unknown
|
|
||||||
): StoredMessageMeta | null {
|
|
||||||
if (!isRecord(value)) return null
|
|
||||||
if (typeof value.id !== "string") return null
|
|
||||||
|
|
||||||
const roleValue = value.role
|
|
||||||
const role: StoredMessageMeta["role"] = roleValue === "assistant" ? "assistant" : "user"
|
|
||||||
|
|
||||||
const created =
|
|
||||||
isRecord(value.time) && typeof value.time.created === "number"
|
|
||||||
? value.time.created
|
|
||||||
: 0
|
|
||||||
|
|
||||||
return {
|
|
||||||
id: value.id,
|
|
||||||
sessionID,
|
|
||||||
role,
|
|
||||||
time: { created },
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
export function readMessages(sessionID: string): StoredMessageMeta[] {
|
export function readMessages(sessionID: string): StoredMessageMeta[] {
|
||||||
if (isSqliteBackend()) return []
|
if (isSqliteBackend()) return []
|
||||||
|
|
||||||
@ -58,27 +28,3 @@ export function readMessages(sessionID: string): StoredMessageMeta[] {
|
|||||||
return a.id.localeCompare(b.id)
|
return a.id.localeCompare(b.id)
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
export async function readMessagesFromSDK(
|
|
||||||
client: OpencodeClient,
|
|
||||||
sessionID: string
|
|
||||||
): Promise<StoredMessageMeta[]> {
|
|
||||||
try {
|
|
||||||
const response = await client.session.messages({ path: { id: sessionID } })
|
|
||||||
const data: unknown = response.data
|
|
||||||
if (!Array.isArray(data)) return []
|
|
||||||
|
|
||||||
const messages = data
|
|
||||||
.map((msg): StoredMessageMeta | null => normalizeSDKMessage(sessionID, msg))
|
|
||||||
.filter((msg): msg is StoredMessageMeta => msg !== null)
|
|
||||||
|
|
||||||
return messages.sort((a, b) => {
|
|
||||||
const aTime = a.time?.created ?? 0
|
|
||||||
const bTime = b.time?.created ?? 0
|
|
||||||
if (aTime !== bTime) return aTime - bTime
|
|
||||||
return a.id.localeCompare(b.id)
|
|
||||||
})
|
|
||||||
} catch {
|
|
||||||
return []
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|||||||
@ -1,5 +1,5 @@
|
|||||||
import { describe, expect, it } from "bun:test"
|
import { describe, expect, it } from "bun:test"
|
||||||
import { readMessagesFromSDK, readPartsFromSDK } from "../storage"
|
import { readPartsFromSDK } from "../storage"
|
||||||
import { readMessages } from "./messages-reader"
|
import { readMessages } from "./messages-reader"
|
||||||
import { readParts } from "./parts-reader"
|
import { readParts } from "./parts-reader"
|
||||||
|
|
||||||
@ -56,28 +56,6 @@ describe("session-recovery storage SDK readers", () => {
|
|||||||
expect(result).toEqual(storedParts)
|
expect(result).toEqual(storedParts)
|
||||||
})
|
})
|
||||||
|
|
||||||
it("readMessagesFromSDK normalizes and sorts messages", async () => {
|
|
||||||
//#given a client that returns messages list
|
|
||||||
const sessionID = "ses_test"
|
|
||||||
const client = createMockClient({
|
|
||||||
messages: () => [
|
|
||||||
{ id: "msg_b", role: "assistant", time: { created: 2 } },
|
|
||||||
{ id: "msg_a", role: "user", time: { created: 1 } },
|
|
||||||
{ id: "msg_c" },
|
|
||||||
],
|
|
||||||
}) as Parameters<typeof readMessagesFromSDK>[0]
|
|
||||||
|
|
||||||
//#when readMessagesFromSDK is called
|
|
||||||
const result = await readMessagesFromSDK(client, sessionID)
|
|
||||||
|
|
||||||
//#then it returns sorted StoredMessageMeta with defaults
|
|
||||||
expect(result).toEqual([
|
|
||||||
{ id: "msg_c", sessionID, role: "user", time: { created: 0 } },
|
|
||||||
{ id: "msg_a", sessionID, role: "user", time: { created: 1 } },
|
|
||||||
{ id: "msg_b", sessionID, role: "assistant", time: { created: 2 } },
|
|
||||||
])
|
|
||||||
})
|
|
||||||
|
|
||||||
it("readParts returns empty array for nonexistent message", () => {
|
it("readParts returns empty array for nonexistent message", () => {
|
||||||
//#given a message ID that has no stored parts
|
//#given a message ID that has no stored parts
|
||||||
//#when readParts is called
|
//#when readParts is called
|
||||||
|
|||||||
@ -74,7 +74,7 @@ export async function patchPart(
|
|||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
const url = `${baseUrl}/session/${sessionID}/message/${messageID}/part/${partID}`
|
const url = `${baseUrl}/session/${encodeURIComponent(sessionID)}/message/${encodeURIComponent(messageID)}/part/${encodeURIComponent(partID)}`
|
||||||
|
|
||||||
try {
|
try {
|
||||||
const response = await fetch(url, {
|
const response = await fetch(url, {
|
||||||
@ -117,7 +117,7 @@ export async function deletePart(
|
|||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
const url = `${baseUrl}/session/${sessionID}/message/${messageID}/part/${partID}`
|
const url = `${baseUrl}/session/${encodeURIComponent(sessionID)}/message/${encodeURIComponent(messageID)}/part/${encodeURIComponent(partID)}`
|
||||||
|
|
||||||
try {
|
try {
|
||||||
const response = await fetch(url, {
|
const response = await fetch(url, {
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user