feat(core): add session snapshot and revert system (#33226)

This commit is contained in:
Dax 2026-06-24 19:41:16 -04:00 committed by GitHub
commit 9bb5370205
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
42 changed files with 2311 additions and 365 deletions

View file

@ -12,6 +12,7 @@ export { Permission } from "./permission"
export { Project } from "./project"
export { Provider } from "./provider"
export { Reference } from "./reference"
export { Revert } from "./revert"
export { Session } from "./session"
export { SessionInput } from "./session-input"
export { SessionMessage } from "./session-message"

View file

@ -0,0 +1,23 @@
export * as Revert from "./revert"
import { Schema } from "effect"
import { NonNegativeInt, RelativePath } from "./schema"
import { SessionMessageID } from "./session-message-id"
export const FileDiff = Schema.Struct({
path: RelativePath,
status: Schema.Literals(["added", "modified", "deleted"]),
additions: NonNegativeInt,
deletions: NonNegativeInt,
patch: Schema.String,
}).annotate({ identifier: "File.Diff" })
export type FileDiff = typeof FileDiff.Type
export const State = Schema.Struct({
messageID: SessionMessageID.ID,
partID: Schema.String.pipe(Schema.optional),
snapshot: Schema.String.pipe(Schema.optional),
diff: Schema.String.pipe(Schema.optional),
files: Schema.Array(FileDiff).pipe(Schema.optional),
})
export type State = typeof State.Type

View file

@ -11,6 +11,7 @@ import { SessionID } from "./session-id"
import { Location } from "./location"
import { SessionMessageID } from "./session-message-id"
import { SessionMessage } from "./session-message"
import { Revert } from "./revert"
export { FileAttachment }
@ -176,6 +177,7 @@ export namespace Step {
}),
}),
snapshot: Schema.String.pipe(Schema.optional),
files: Schema.Array(RelativePath).pipe(Schema.optional),
},
})
export type Ended = typeof Ended.Type
@ -429,6 +431,20 @@ export namespace Compaction {
export type Ended = typeof Ended.Type
}
export namespace RevertEvent {
export const Staged = Event.define({
type: "session.next.revert.staged",
...options,
schema: { ...Base, revert: Revert.State },
})
export const Cleared = Event.define({ type: "session.next.revert.cleared", ...options, schema: Base })
export const Committed = Event.define({
type: "session.next.revert.committed",
...options,
schema: { ...Base, messageID: SessionMessageID.ID },
})
}
export const DurableDefinitions = Event.inventory(
AgentSwitched,
ModelSwitched,
@ -455,6 +471,9 @@ export const DurableDefinitions = Event.inventory(
Retried,
Compaction.Started,
Compaction.Ended,
RevertEvent.Staged,
RevertEvent.Cleared,
RevertEvent.Committed,
)
export const Definitions = Event.inventory(
@ -487,6 +506,9 @@ export const Definitions = Event.inventory(
Compaction.Started,
Compaction.Delta,
Compaction.Ended,
RevertEvent.Staged,
RevertEvent.Cleared,
RevertEvent.Committed,
)
export const Durable = Schema.Union(DurableDefinitions, { mode: "oneOf" }).pipe(Schema.toTaggedUnion("type"))

View file

@ -4,7 +4,7 @@ import { Schema } from "effect"
import { ProviderMetadata, ToolContent } from "./llm"
import { Model } from "./model"
import { FileAttachment, Prompt } from "./prompt"
import { DateTimeUtcFromMillis } from "./schema"
import { DateTimeUtcFromMillis, RelativePath } from "./schema"
import { SessionID } from "./session-id"
import { SessionMessageID } from "./session-message-id"
@ -163,6 +163,7 @@ export const Assistant = Schema.Struct({
snapshot: Schema.Struct({
start: Schema.String.pipe(Schema.optional),
end: Schema.String.pipe(Schema.optional),
files: Schema.Array(RelativePath).pipe(Schema.optional),
}).pipe(Schema.optional),
finish: Schema.String.pipe(Schema.optional),
cost: Schema.Finite.pipe(Schema.optional),

View file

@ -8,6 +8,7 @@ import { Project } from "./project"
import { DateTimeUtcFromMillis, optionalOmitUndefined, RelativePath } from "./schema"
import { SessionEvent } from "./session-event"
import { SessionID } from "./session-id"
import { Revert } from "./revert"
export const ID = SessionID
export type ID = SessionID
@ -39,6 +40,7 @@ export const Info = Schema.Struct({
title: Schema.String,
location: Location.Ref,
subpath: RelativePath.pipe(Schema.optional),
revert: Revert.State.pipe(Schema.optional),
}).annotate({ identifier: "SessionV2.Info" })
export const ListAnchor = Schema.Struct({