1- import { ulid } from "ulid "
1+ import { createHash } from "node:crypto "
22import { isMessageCompacted } from "../shared-utils"
33import { Logger } from "../logger"
44import type { SessionState , WithParts } from "../state"
55import 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
914type MessagePart = WithParts [ "parts" ] [ number ]
1015type 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 = (
5056export 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 )
0 commit comments