























@@ -55,6 +55,52 @@ function isUserAgentMessage(message: AgentMessage): message is UserAgentMessage
5555return message.role === "user";
5656}
575758+type TranscriptSeqByEntryId = Map<string, number>;
59+60+function resolveEntryTranscriptSeq(
61+sessionManager: SessionManager,
62+entryId: string | null | undefined,
63+seqByEntryId: TranscriptSeqByEntryId,
64+): number | undefined {
65+if (!entryId) {
66+return 0;
67+}
68+const cached = seqByEntryId.get(entryId);
69+if (cached !== undefined) {
70+return cached;
71+}
72+let seq = 0;
73+for (const entry of sessionManager.getBranch(entryId)) {
74+if (entry.type === "message" || entry.type === "compaction") {
75+seq += 1;
76+}
77+seqByEntryId.set(entry.id, seq);
78+}
79+return seqByEntryId.get(entryId);
80+}
81+82+function resolveAppendedMessageSeq(params: {
83+sessionManager: SessionManager;
84+entryId: unknown;
85+parentEntryId: string | null | undefined;
86+seqByEntryId: TranscriptSeqByEntryId;
87+}): number | undefined {
88+if (typeof params.entryId !== "string") {
89+return undefined;
90+}
91+const parentSeq = resolveEntryTranscriptSeq(
92+params.sessionManager,
93+params.parentEntryId,
94+params.seqByEntryId,
95+);
96+if (parentSeq === undefined) {
97+return undefined;
98+}
99+const messageSeq = parentSeq + 1;
100+params.seqByEntryId.set(params.entryId, messageSeq);
101+return messageSeq;
102+}
103+58104// `details` is runtime/UI metadata, not model-visible tool output. Keep the
59105// session JSONL useful for debugging without letting metadata blobs dominate
60106// disk, replay repair, transcript broadcasts, or future tooling that reads raw
@@ -536,8 +582,33 @@ export function installSessionToolResultGuard(
536582const beforeWrite = opts?.beforeMessageWriteHook;
537583const redactionConfig = opts?.redactLoggingConfig;
538584const maxToolResultChars = resolveMaxToolResultChars(opts);
585+const transcriptSeqByEntryId: TranscriptSeqByEntryId = new Map();
539586let suppressNextUserMessagePersistence = opts?.suppressNextUserMessagePersistence === true;
540587588+const getSessionFile = () =>
589+(sessionManager as { getSessionFile?: () => string | null }).getSessionFile?.();
590+591+const appendMessageAndCacheTranscriptSeq = (
592+message: AgentMessage,
593+): { entryId: string; messageSeq?: number; sessionFile?: string | null } => {
594+const parentEntryId = sessionManager.getLeafId();
595+const entryId = originalAppend(message as never);
596+const sessionFile = getSessionFile();
597+if (!sessionFile) {
598+return { entryId, sessionFile };
599+}
600+return {
601+ entryId,
602+ sessionFile,
603+messageSeq: resolveAppendedMessageSeq({
604+ sessionManager,
605+ entryId,
606+ parentEntryId,
607+seqByEntryId: transcriptSeqByEntryId,
608+}),
609+};
610+};
611+541612/**
542613 * Run the before_message_write hook. Returns the (possibly modified) message,
543614 * or null if the message should be blocked.
@@ -575,8 +646,8 @@ export function installSessionToolResultGuard(
575646}),
576647);
577648if (flushed) {
578-originalAppend(
579-capToolResultForPersistence(flushed, maxToolResultChars, redactionConfig) as never,
649+appendMessageAndCacheTranscriptSeq(
650+capToolResultForPersistence(flushed, maxToolResultChars, redactionConfig),
580651);
581652}
582653}
@@ -629,9 +700,9 @@ export function installSessionToolResultGuard(
629700if (!persisted) {
630701return undefined;
631702}
632-return originalAppend(
633-capToolResultForPersistence(persisted, maxToolResultChars, redactionConfig) as never,
634-);
703+return appendMessageAndCacheTranscriptSeq(
704+capToolResultForPersistence(persisted, maxToolResultChars, redactionConfig),
705+).entryId;
635706}
636707637708// Skip tool call extraction for aborted/errored assistant messages.
@@ -675,17 +746,18 @@ export function installSessionToolResultGuard(
675746suppressNextUserMessagePersistence = false;
676747return undefined;
677748}
678-const result = originalAppend(finalMessage as never);
679-680-const sessionFile = (
681-sessionManager as { getSessionFile?: () => string | null }
682-).getSessionFile?.();
749+const {
750+ entryId: result,
751+ messageSeq,
752+sessionFile,
753+} = appendMessageAndCacheTranscriptSeq(finalMessage);
683754if (sessionFile) {
684755emitSessionTranscriptUpdate({
685756 sessionFile,
686757sessionKey: opts?.sessionKey,
687758message: finalMessage,
688759messageId: typeof result === "string" ? result : undefined,
760+ ...(messageSeq !== undefined ? { messageSeq } : {}),
689761});
690762}
691763此内容由惯性聚合(RSS阅读器)自动聚合整理,仅供阅读参考。 原文来自 — 版权归原作者所有。