Skip to content

Commit e8fe159

Browse files
committed
refactor: make synthetic injection IDs deterministic
1 parent 36353b1 commit e8fe159

File tree

3 files changed

+18
-21
lines changed

3 files changed

+18
-21
lines changed

lib/messages/utils.ts

Lines changed: 18 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,15 @@
1-
import { ulid } from "ulid"
1+
import { createHash } from "node:crypto"
22
import { isMessageCompacted } from "../shared-utils"
33
import { Logger } from "../logger"
44
import type { SessionState, WithParts } from "../state"
55
import type { UserMessage } from "@opencode-ai/sdk/v2"
66

7-
const generateUniqueId = (prefix: string): string => `${prefix}_${ulid()}`
7+
const SUMMARY_ID_HASH_LENGTH = 16
8+
9+
const generateStableId = (prefix: string, seed: string): string => {
10+
const hash = createHash("sha256").update(seed).digest("hex").slice(0, SUMMARY_ID_HASH_LENGTH)
11+
return `${prefix}_${hash}`
12+
}
813

914
type MessagePart = WithParts["parts"][number]
1015
type ToolPart = Extract<MessagePart, { type: "tool" }>
@@ -18,12 +23,13 @@ export const createSyntheticUserMessage = (
1823
baseMessage: WithParts,
1924
content: string,
2025
variant?: string,
21-
_stableSeed?: string,
26+
stableSeed?: string,
2227
): WithParts => {
2328
const userInfo = baseMessage.info as UserMessage
2429
const now = Date.now()
25-
const messageId = generateUniqueId("msg")
26-
const partId = generateUniqueId("prt")
30+
const deterministicSeed = stableSeed?.trim() || userInfo.id
31+
const messageId = generateStableId("msg_dcp_summary", deterministicSeed)
32+
const partId = generateStableId("prt_dcp_summary", deterministicSeed)
2733

2834
return {
2935
info: {
@@ -50,10 +56,11 @@ export const createSyntheticUserMessage = (
5056
export const createSyntheticTextPart = (
5157
baseMessage: WithParts,
5258
content: string,
53-
_stableSeed?: string,
59+
stableSeed?: string,
5460
) => {
5561
const userInfo = baseMessage.info as UserMessage
56-
const partId = generateUniqueId("prt")
62+
const deterministicSeed = stableSeed?.trim() || userInfo.id
63+
const partId = generateStableId("prt_dcp_text", deterministicSeed)
5764

5865
return {
5966
id: partId,
@@ -68,13 +75,14 @@ export const createSyntheticToolPart = (
6875
baseMessage: WithParts,
6976
content: string,
7077
modelID: string,
71-
_stableSeed?: string,
78+
stableSeed?: string,
7279
) => {
7380
const userInfo = baseMessage.info as UserMessage
7481
const now = Date.now()
7582

76-
const partId = generateUniqueId("prt")
77-
const callId = generateUniqueId("call")
83+
const deterministicSeed = stableSeed?.trim() || userInfo.id
84+
const partId = generateStableId("prt_dcp_tool", deterministicSeed)
85+
const callId = generateStableId("call_dcp_tool", deterministicSeed)
7886

7987
// Gemini requires thoughtSignature bypass to accept synthetic tool parts
8088
const toolPartMetadata = isGeminiModel(modelID)

package-lock.json

Lines changed: 0 additions & 10 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

package.json

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -45,7 +45,6 @@
4545
"@anthropic-ai/tokenizer": "^0.0.4",
4646
"@opencode-ai/sdk": "^1.1.48",
4747
"jsonc-parser": "^3.3.1",
48-
"ulid": "^3.0.2",
4948
"zod": "^4.3.6"
5049
},
5150
"devDependencies": {

0 commit comments

Comments
 (0)