mirror of
https://github.com/openclaw/openclaw.git
synced 2026-08-28 13:26:04 -06:00
fix(copilot): keep tool transcript groups structurally complete (#114403)
* refactor(copilot): make SQLite own transcripts * fix(copilot): harden transcript event projection * test(copilot): tighten transcript journal types * fix(copilot): retain unmatched usage metadata * refactor(copilot): commit tool groups atomically * fix(copilot): break journal bridge import cycle * fix(copilot): preserve grouped transcript replay * test(copilot): cover opaque replay state * fix(copilot): invalidate lossy transcript replay * fix(copilot): guard transcript rewrite topology * fix(copilot): drain transcript finalization * fix(copilot): preserve resumed session history * fix(copilot): dedupe replayed transcript snapshots * fix(copilot): isolate transcript write hooks * fix(copilot): track staged transcript identities * fix(copilot): isolate ephemeral transcript events * fix(copilot): coalesce assistant snapshots * fix(copilot): invalidate unprojected SDK context * fix(copilot): guard resumed transcript replay * fix(plugin-sdk): expose strict transcript append * fix(copilot): persist journal provenance safely * fix(copilot): separate live and durable deltas * fix(copilot): require durable projection ownership * fix(copilot): preserve strict append typing * fix(copilot): gate deferred session deletion * fix(copilot): preserve transcript replay identity * fix(copilot): retain cited replay history * fix(copilot): require complete replay provenance * fix(copilot): reject ambiguous assistant snapshots * fix(copilot): return latest assistant snapshot * chore(copilot): align transcript lint gates * test(lint): cover Copilot line budgets * test(ci): dedupe Codex prewarm shard
This commit is contained in:
committed by
GitHub
parent
bbc73c36bd
commit
3dc3370d9e
@@ -2,10 +2,12 @@ import { isRecord } from "@openclaw/normalization-core/record-coerce";
|
||||
import { redactTranscriptMessage } from "../agents/transcript-redact.js";
|
||||
import {
|
||||
appendTranscriptMessage,
|
||||
appendTranscriptMessages,
|
||||
isSessionTranscriptProjectionUnavailableError,
|
||||
loadSessionEntry,
|
||||
loadTranscriptEvents,
|
||||
publishTranscriptUpdate,
|
||||
persistSessionTranscriptTurn,
|
||||
readTranscriptRawDelta,
|
||||
readSessionTranscriptVisibleMessageDelta as readVisibleMessageDelta,
|
||||
readLatestTranscriptAssistantText,
|
||||
@@ -128,6 +130,20 @@ export type SessionTranscriptTarget = SessionTranscriptIdentity & {
|
||||
export type SessionTranscriptAppendMessageParams<TMessage> = SessionTranscriptTargetParams &
|
||||
TranscriptMessageAppendOptions<TMessage>;
|
||||
|
||||
export type SessionTranscriptAppendMessagesParams<TMessage> = SessionTranscriptTargetParams & {
|
||||
config?: TranscriptMessageAppendOptions<TMessage>["config"];
|
||||
cwd?: string;
|
||||
messages: readonly Omit<
|
||||
TranscriptMessageAppendOptions<TMessage>,
|
||||
"config" | "cwd" | "parentId" | "prepareMessageAfterIdempotencyCheck" | "useRawWhenLinear"
|
||||
>[];
|
||||
};
|
||||
|
||||
export type SessionTranscriptStrictMessageAppendResult<TMessage> =
|
||||
| { kind: "result"; result: TranscriptMessageAppendResult<TMessage> }
|
||||
| { kind: "suppressed" }
|
||||
| { kind: "rejected"; reason: "session-rebound" };
|
||||
|
||||
export type SessionTranscriptAssistantMirrorAppendParams = SessionTranscriptReadParams & {
|
||||
config?: OpenClawConfig;
|
||||
deliveryMirror?: SessionTranscriptDeliveryMirror;
|
||||
@@ -345,6 +361,57 @@ export async function appendSessionTranscriptMessageByIdentity<TMessage>(
|
||||
return await appendTranscriptMessage(params, params);
|
||||
}
|
||||
|
||||
/** Appends one message while preserving distinct suppression and session-rebind outcomes. */
|
||||
export async function appendSessionTranscriptMessageByIdentityStrict<TMessage>(
|
||||
params: SessionTranscriptAppendMessageParams<TMessage>,
|
||||
): Promise<SessionTranscriptStrictMessageAppendResult<TMessage>> {
|
||||
const expectedSessionId = params.sessionId?.trim();
|
||||
if (!expectedSessionId) {
|
||||
throw new Error("Cannot strictly append a transcript message without an exact session id");
|
||||
}
|
||||
const turn = await persistSessionTranscriptTurn(params, {
|
||||
...(params.config ? { config: params.config } : {}),
|
||||
...(params.cwd ? { cwd: params.cwd } : {}),
|
||||
expectedSessionId,
|
||||
messages: [
|
||||
{
|
||||
...(params.eventId !== undefined ? { eventId: params.eventId } : {}),
|
||||
...(params.idempotencyLookup !== undefined
|
||||
? { idempotencyLookup: params.idempotencyLookup }
|
||||
: {}),
|
||||
message: params.message,
|
||||
...(params.now !== undefined ? { now: params.now } : {}),
|
||||
...(params.parentId !== undefined ? { parentId: params.parentId } : {}),
|
||||
...(params.prepareMessageAfterIdempotencyCheck
|
||||
? {
|
||||
prepareMessageAfterIdempotencyCheck: (message: unknown) =>
|
||||
params.prepareMessageAfterIdempotencyCheck?.(message as TMessage),
|
||||
}
|
||||
: {}),
|
||||
...(params.useRawWhenLinear !== undefined
|
||||
? { useRawWhenLinear: params.useRawWhenLinear }
|
||||
: {}),
|
||||
},
|
||||
],
|
||||
updateMode: "none",
|
||||
});
|
||||
if (turn.rejectedReason) {
|
||||
return { kind: "rejected", reason: turn.rejectedReason };
|
||||
}
|
||||
const result = turn.messages[0] as TranscriptMessageAppendResult<TMessage> | undefined;
|
||||
return result ? { kind: "result", result } : { kind: "suppressed" };
|
||||
}
|
||||
|
||||
/**
|
||||
* Atomically appends one ordered, already-hooked message group. Preparation and
|
||||
* redaction finish before SQLite begins; this is the canonical future harness seam.
|
||||
*/
|
||||
export async function appendSessionTranscriptMessagesByIdentity<TMessage>(
|
||||
params: SessionTranscriptAppendMessagesParams<TMessage>,
|
||||
): Promise<TranscriptMessageAppendResult<TMessage>[]> {
|
||||
return await appendTranscriptMessages(params, params);
|
||||
}
|
||||
|
||||
/**
|
||||
* Publishes a transcript update by scoped transcript target.
|
||||
*/
|
||||
|
||||
Reference in New Issue
Block a user