mirror of
https://github.com/aljazceru/opencode.git
synced 2025-12-22 10:14:22 +01:00
wip: more snapshot stuff
This commit is contained in:
@@ -5,76 +5,30 @@ import { cmd } from "../cmd"
|
||||
|
||||
export const SnapshotCommand = cmd({
|
||||
command: "snapshot",
|
||||
builder: (yargs) =>
|
||||
yargs.command(CreateCommand).command(RestoreCommand).command(DiffCommand).command(RevertCommand).demandCommand(),
|
||||
builder: (yargs) => yargs.command(TrackCommand).command(PatchCommand).demandCommand(),
|
||||
async handler() {},
|
||||
})
|
||||
|
||||
const CreateCommand = cmd({
|
||||
command: "create",
|
||||
const TrackCommand = cmd({
|
||||
command: "track",
|
||||
async handler() {
|
||||
await bootstrap({ cwd: process.cwd() }, async () => {
|
||||
const result = await Snapshot.create()
|
||||
console.log(result)
|
||||
console.log(await Snapshot.track())
|
||||
})
|
||||
},
|
||||
})
|
||||
|
||||
const RestoreCommand = cmd({
|
||||
command: "restore <commit>",
|
||||
const PatchCommand = cmd({
|
||||
command: "patch <hash>",
|
||||
builder: (yargs) =>
|
||||
yargs.positional("commit", {
|
||||
yargs.positional("hash", {
|
||||
type: "string",
|
||||
description: "commit",
|
||||
description: "hash",
|
||||
demandOption: true,
|
||||
}),
|
||||
async handler(args) {
|
||||
await bootstrap({ cwd: process.cwd() }, async () => {
|
||||
await Snapshot.restore(args.commit)
|
||||
console.log("restored")
|
||||
})
|
||||
},
|
||||
})
|
||||
|
||||
export const DiffCommand = cmd({
|
||||
command: "diff <commit>",
|
||||
describe: "diff",
|
||||
builder: (yargs) =>
|
||||
yargs.positional("commit", {
|
||||
type: "string",
|
||||
description: "commit",
|
||||
demandOption: true,
|
||||
}),
|
||||
async handler(args) {
|
||||
await bootstrap({ cwd: process.cwd() }, async () => {
|
||||
const diff = await Snapshot.diff(args.commit)
|
||||
console.log(diff)
|
||||
})
|
||||
},
|
||||
})
|
||||
|
||||
export const RevertCommand = cmd({
|
||||
command: "revert <sessionID> <messageID>",
|
||||
describe: "revert",
|
||||
builder: (yargs) =>
|
||||
yargs
|
||||
.positional("sessionID", {
|
||||
type: "string",
|
||||
description: "sessionID",
|
||||
demandOption: true,
|
||||
})
|
||||
.positional("messageID", {
|
||||
type: "string",
|
||||
description: "messageID",
|
||||
demandOption: true,
|
||||
}),
|
||||
async handler(args) {
|
||||
await bootstrap({ cwd: process.cwd() }, async () => {
|
||||
const session = await Session.revert({
|
||||
sessionID: args.sessionID,
|
||||
messageID: args.messageID,
|
||||
})
|
||||
console.log(session?.revert)
|
||||
console.log(await Snapshot.patch(args.hash))
|
||||
})
|
||||
},
|
||||
})
|
||||
|
||||
@@ -661,6 +661,7 @@ export namespace Session {
|
||||
description: item.description,
|
||||
inputSchema: item.parameters as ZodSchema,
|
||||
async execute(args, options) {
|
||||
await processor.track(options.toolCallId)
|
||||
const result = await item.execute(args, {
|
||||
sessionID: input.sessionID,
|
||||
abort: abort.signal,
|
||||
@@ -699,6 +700,7 @@ export namespace Session {
|
||||
const execute = item.execute
|
||||
if (!execute) continue
|
||||
item.execute = async (args, opts) => {
|
||||
await processor.track(opts.toolCallId)
|
||||
const result = await execute(args, opts)
|
||||
const output = result.content
|
||||
.filter((x: any) => x.type === "text")
|
||||
@@ -814,7 +816,12 @@ export namespace Session {
|
||||
|
||||
function createProcessor(assistantMsg: MessageV2.Assistant, model: ModelsDev.Model) {
|
||||
const toolCalls: Record<string, MessageV2.ToolPart> = {}
|
||||
const snapshots: Record<string, string> = {}
|
||||
return {
|
||||
async track(toolCallID: string) {
|
||||
const hash = await Snapshot.track()
|
||||
if (hash) snapshots[toolCallID] = hash
|
||||
},
|
||||
partFromToolCall(toolCallID: string) {
|
||||
return toolCalls[toolCallID]
|
||||
},
|
||||
@@ -828,15 +835,6 @@ export namespace Session {
|
||||
})
|
||||
switch (value.type) {
|
||||
case "start":
|
||||
const snapshot = await Snapshot.create()
|
||||
if (snapshot)
|
||||
await updatePart({
|
||||
id: Identifier.ascending("part"),
|
||||
messageID: assistantMsg.id,
|
||||
sessionID: assistantMsg.sessionID,
|
||||
type: "snapshot",
|
||||
snapshot,
|
||||
})
|
||||
break
|
||||
|
||||
case "tool-input-start":
|
||||
@@ -857,6 +855,9 @@ export namespace Session {
|
||||
case "tool-input-delta":
|
||||
break
|
||||
|
||||
case "tool-input-end":
|
||||
break
|
||||
|
||||
case "tool-call": {
|
||||
const match = toolCalls[value.toolCallId]
|
||||
if (match) {
|
||||
@@ -892,16 +893,21 @@ export namespace Session {
|
||||
},
|
||||
})
|
||||
delete toolCalls[value.toolCallId]
|
||||
const snapshot = await Snapshot.create()
|
||||
if (snapshot)
|
||||
const snapshot = snapshots[value.toolCallId]
|
||||
if (snapshot) {
|
||||
const patch = await Snapshot.patch(snapshot)
|
||||
if (patch.files.length) {
|
||||
await updatePart({
|
||||
id: Identifier.ascending("part"),
|
||||
messageID: assistantMsg.id,
|
||||
sessionID: assistantMsg.sessionID,
|
||||
type: "snapshot",
|
||||
snapshot,
|
||||
type: "patch",
|
||||
hash: patch.hash,
|
||||
files: patch.files,
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
break
|
||||
}
|
||||
|
||||
@@ -921,16 +927,19 @@ export namespace Session {
|
||||
},
|
||||
})
|
||||
delete toolCalls[value.toolCallId]
|
||||
const snapshot = await Snapshot.create()
|
||||
if (snapshot)
|
||||
const snapshot = snapshots[value.toolCallId]
|
||||
if (snapshot) {
|
||||
const patch = await Snapshot.patch(snapshot)
|
||||
await updatePart({
|
||||
id: Identifier.ascending("part"),
|
||||
messageID: assistantMsg.id,
|
||||
sessionID: assistantMsg.sessionID,
|
||||
type: "snapshot",
|
||||
snapshot,
|
||||
type: "patch",
|
||||
hash: patch.hash,
|
||||
files: patch.files,
|
||||
})
|
||||
}
|
||||
}
|
||||
break
|
||||
}
|
||||
|
||||
@@ -1073,35 +1082,47 @@ export namespace Session {
|
||||
|
||||
export async function revert(input: RevertInput) {
|
||||
const all = await messages(input.sessionID)
|
||||
const session = await get(input.sessionID)
|
||||
let lastUser: MessageV2.User | undefined
|
||||
let lastSnapshot: MessageV2.SnapshotPart | undefined
|
||||
const session = await get(input.sessionID)
|
||||
|
||||
let revert: Info["revert"]
|
||||
const patches: Snapshot.Patch[] = []
|
||||
for (const msg of all) {
|
||||
if (msg.info.role === "user") lastUser = msg.info
|
||||
const remaining = []
|
||||
for (const part of msg.parts) {
|
||||
if (part.type === "snapshot") lastSnapshot = part
|
||||
if (revert) {
|
||||
if (part.type === "patch") {
|
||||
patches.push(part)
|
||||
}
|
||||
continue
|
||||
}
|
||||
|
||||
if (!revert) {
|
||||
if ((msg.info.id === input.messageID && !input.partID) || part.id === input.partID) {
|
||||
// if no useful parts left in message, same as reverting whole message
|
||||
const partID = remaining.some((item) => ["text", "tool"].includes(item.type)) ? input.partID : undefined
|
||||
const snapshot = session.revert?.snapshot ?? (await Snapshot.create())
|
||||
log.info("revert snapshot", { snapshot })
|
||||
if (lastSnapshot) await Snapshot.restore(lastSnapshot.snapshot)
|
||||
const next = await update(input.sessionID, (draft) => {
|
||||
draft.revert = {
|
||||
// if not part id jump to the last user message
|
||||
revert = {
|
||||
messageID: !partID && lastUser ? lastUser.id : msg.info.id,
|
||||
partID,
|
||||
snapshot,
|
||||
}
|
||||
})
|
||||
return next
|
||||
}
|
||||
remaining.push(part)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (revert) {
|
||||
const session = await get(input.sessionID)
|
||||
revert.snapshot = session.revert?.snapshot ?? (await Snapshot.track())
|
||||
await Snapshot.revert(patches)
|
||||
return update(input.sessionID, (draft) => {
|
||||
draft.revert = revert
|
||||
})
|
||||
}
|
||||
return session
|
||||
}
|
||||
|
||||
export async function unrevert(input: { sessionID: string }) {
|
||||
log.info("unreverting", input)
|
||||
const session = await get(input.sessionID)
|
||||
|
||||
@@ -94,6 +94,15 @@ export namespace MessageV2 {
|
||||
})
|
||||
export type SnapshotPart = z.infer<typeof SnapshotPart>
|
||||
|
||||
export const PatchPart = PartBase.extend({
|
||||
type: z.literal("patch"),
|
||||
hash: z.string(),
|
||||
files: z.string().array(),
|
||||
}).openapi({
|
||||
ref: "PatchPart",
|
||||
})
|
||||
export type PatchPart = z.infer<typeof PatchPart>
|
||||
|
||||
export const TextPart = PartBase.extend({
|
||||
type: z.literal("text"),
|
||||
text: z.string(),
|
||||
@@ -203,7 +212,7 @@ export namespace MessageV2 {
|
||||
export type User = z.infer<typeof User>
|
||||
|
||||
export const Part = z
|
||||
.discriminatedUnion("type", [TextPart, FilePart, ToolPart, StepStartPart, StepFinishPart, SnapshotPart])
|
||||
.discriminatedUnion("type", [TextPart, FilePart, ToolPart, StepStartPart, StepFinishPart, SnapshotPart, PatchPart])
|
||||
.openapi({
|
||||
ref: "Part",
|
||||
})
|
||||
|
||||
@@ -6,6 +6,7 @@ import { Ripgrep } from "../file/ripgrep"
|
||||
import { Log } from "../util/log"
|
||||
import { Global } from "../global"
|
||||
import { Installation } from "../installation"
|
||||
import { z } from "zod"
|
||||
|
||||
export namespace Snapshot {
|
||||
const log = Log.create({ service: "snapshot" })
|
||||
@@ -24,21 +25,9 @@ export namespace Snapshot {
|
||||
})
|
||||
}
|
||||
|
||||
export async function create() {
|
||||
log.info("creating snapshot")
|
||||
export async function track() {
|
||||
const app = App.info()
|
||||
|
||||
// not a git repo, check if too big to snapshot
|
||||
if (!app.git || !Installation.isDev()) {
|
||||
return
|
||||
const files = await Ripgrep.files({
|
||||
cwd: app.path.cwd,
|
||||
limit: 1000,
|
||||
})
|
||||
log.info("found files", { count: files.length })
|
||||
if (files.length >= 1000) return
|
||||
}
|
||||
|
||||
if (!app.git) return
|
||||
const git = gitdir()
|
||||
if (await fs.mkdir(git, { recursive: true })) {
|
||||
await $`git init`
|
||||
@@ -51,33 +40,52 @@ export namespace Snapshot {
|
||||
.nothrow()
|
||||
log.info("initialized")
|
||||
}
|
||||
|
||||
await $`git --git-dir ${git} add .`.quiet().cwd(app.path.cwd).nothrow()
|
||||
log.info("added files")
|
||||
const hash = await $`git --git-dir ${git} write-tree`.quiet().cwd(app.path.cwd).text()
|
||||
return hash.trim()
|
||||
}
|
||||
|
||||
const result =
|
||||
await $`git --git-dir ${git} commit --allow-empty -m "snapshot" --no-gpg-sign --author="opencode <mail@opencode.ai>"`
|
||||
.quiet()
|
||||
.cwd(app.path.cwd)
|
||||
.nothrow()
|
||||
export const Patch = z.object({
|
||||
hash: z.string(),
|
||||
files: z.string().array(),
|
||||
})
|
||||
export type Patch = z.infer<typeof Patch>
|
||||
|
||||
const match = result.stdout.toString().match(/\[.+ ([a-f0-9]+)\]/)
|
||||
if (!match) return
|
||||
return match![1]
|
||||
export async function patch(hash: string): Promise<Patch> {
|
||||
const app = App.info()
|
||||
const git = gitdir()
|
||||
const files = await $`git --git-dir ${git} diff --name-only ${hash} -- .`.cwd(app.path.cwd).text()
|
||||
return {
|
||||
hash,
|
||||
files: files
|
||||
.trim()
|
||||
.split("\n")
|
||||
.map((x) => x.trim())
|
||||
.filter(Boolean)
|
||||
.map((x) => path.join(app.path.cwd, x)),
|
||||
}
|
||||
}
|
||||
|
||||
export async function restore(snapshot: string) {
|
||||
log.info("restore", { commit: snapshot })
|
||||
const app = App.info()
|
||||
const git = gitdir()
|
||||
await $`git --git-dir=${git} reset --hard ${snapshot}`.quiet().cwd(app.path.root)
|
||||
await $`git --git-dir=${git} read-tree ${snapshot} && git --git-dir=${git} checkout-index -a -f`
|
||||
.quiet()
|
||||
.cwd(app.path.root)
|
||||
}
|
||||
|
||||
export async function diff(commit: string) {
|
||||
export async function revert(patches: Patch[]) {
|
||||
const files = new Set<string>()
|
||||
const git = gitdir()
|
||||
const result = await $`git --git-dir=${git} diff -R ${commit}`.quiet().cwd(App.info().path.root)
|
||||
const text = result.stdout.toString("utf8")
|
||||
return text
|
||||
for (const item of patches) {
|
||||
for (const file of item.files) {
|
||||
if (files.has(file)) continue
|
||||
log.info("reverting", { file, hash: item.hash })
|
||||
await $`git --git-dir=${git} checkout ${item.hash} -- ${file}`.quiet().cwd(App.info().path.root)
|
||||
files.add(file)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function gitdir() {
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
configured_endpoints: 26
|
||||
openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/opencode%2Fopencode-1efc45c35b58e88b0550fbb0c7a204ef66522742f87c9e29c76a18b120c0d945.yml
|
||||
openapi_spec_hash: 5e15d85e4704624f9b13bae1c71aa416
|
||||
openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/opencode%2Fopencode-5748199af356c3243a46a466e73b5d0bab7eaa0c56895e1d0f903d637f61d0bb.yml
|
||||
openapi_spec_hash: c04f6b6be54b05d9b1283c24e870163b
|
||||
config_hash: 1ae82c93499b9f0b9ba828b8919f9cb3
|
||||
|
||||
@@ -147,7 +147,7 @@ export namespace Config {
|
||||
|
||||
npm?: string;
|
||||
|
||||
options?: { [key: string]: unknown };
|
||||
options?: Provider.Options;
|
||||
}
|
||||
|
||||
export namespace Provider {
|
||||
@@ -190,6 +190,14 @@ export namespace Config {
|
||||
output: number;
|
||||
}
|
||||
}
|
||||
|
||||
export interface Options {
|
||||
apiKey?: string;
|
||||
|
||||
baseURL?: string;
|
||||
|
||||
[k: string]: unknown;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -24,6 +24,7 @@ export type EventListResponse =
|
||||
| EventListResponse.EventMessageUpdated
|
||||
| EventListResponse.EventMessageRemoved
|
||||
| EventListResponse.EventMessagePartUpdated
|
||||
| EventListResponse.EventMessagePartRemoved
|
||||
| EventListResponse.EventStorageWrite
|
||||
| EventListResponse.EventSessionUpdated
|
||||
| EventListResponse.EventSessionDeleted
|
||||
@@ -135,6 +136,20 @@ export namespace EventListResponse {
|
||||
}
|
||||
}
|
||||
|
||||
export interface EventMessagePartRemoved {
|
||||
properties: EventMessagePartRemoved.Properties;
|
||||
|
||||
type: 'message.part.removed';
|
||||
}
|
||||
|
||||
export namespace EventMessagePartRemoved {
|
||||
export interface Properties {
|
||||
messageID: string;
|
||||
|
||||
partID: string;
|
||||
}
|
||||
}
|
||||
|
||||
export interface EventStorageWrite {
|
||||
properties: EventStorageWrite.Properties;
|
||||
|
||||
|
||||
@@ -102,6 +102,8 @@ export interface AssistantMessage {
|
||||
|
||||
cost: number;
|
||||
|
||||
mode: string;
|
||||
|
||||
modelID: string;
|
||||
|
||||
path: AssistantMessage.Path;
|
||||
@@ -217,7 +219,30 @@ export interface FileSource {
|
||||
|
||||
export type Message = UserMessage | AssistantMessage;
|
||||
|
||||
export type Part = TextPart | FilePart | ToolPart | StepStartPart | StepFinishPart | SnapshotPart;
|
||||
export type Part =
|
||||
| TextPart
|
||||
| FilePart
|
||||
| ToolPart
|
||||
| StepStartPart
|
||||
| StepFinishPart
|
||||
| SnapshotPart
|
||||
| Part.PatchPart;
|
||||
|
||||
export namespace Part {
|
||||
export interface PatchPart {
|
||||
id: string;
|
||||
|
||||
files: Array<string>;
|
||||
|
||||
hash: string;
|
||||
|
||||
messageID: string;
|
||||
|
||||
sessionID: string;
|
||||
|
||||
type: 'patch';
|
||||
}
|
||||
}
|
||||
|
||||
export interface Session {
|
||||
id: string;
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
configured_endpoints: 26
|
||||
openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/opencode%2Fopencode-1efc45c35b58e88b0550fbb0c7a204ef66522742f87c9e29c76a18b120c0d945.yml
|
||||
openapi_spec_hash: 5e15d85e4704624f9b13bae1c71aa416
|
||||
openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/opencode%2Fopencode-5748199af356c3243a46a466e73b5d0bab7eaa0c56895e1d0f903d637f61d0bb.yml
|
||||
openapi_spec_hash: c04f6b6be54b05d9b1283c24e870163b
|
||||
config_hash: 1ae82c93499b9f0b9ba828b8919f9cb3
|
||||
|
||||
@@ -333,7 +333,7 @@ type ConfigProvider struct {
|
||||
Env []string `json:"env"`
|
||||
Name string `json:"name"`
|
||||
Npm string `json:"npm"`
|
||||
Options map[string]interface{} `json:"options"`
|
||||
Options ConfigProviderOptions `json:"options"`
|
||||
JSON configProviderJSON `json:"-"`
|
||||
}
|
||||
|
||||
@@ -447,6 +447,30 @@ func (r configProviderModelsLimitJSON) RawJSON() string {
|
||||
return r.raw
|
||||
}
|
||||
|
||||
type ConfigProviderOptions struct {
|
||||
APIKey string `json:"apiKey"`
|
||||
BaseURL string `json:"baseURL"`
|
||||
ExtraFields map[string]interface{} `json:"-,extras"`
|
||||
JSON configProviderOptionsJSON `json:"-"`
|
||||
}
|
||||
|
||||
// configProviderOptionsJSON contains the JSON metadata for the struct
|
||||
// [ConfigProviderOptions]
|
||||
type configProviderOptionsJSON struct {
|
||||
APIKey apijson.Field
|
||||
BaseURL apijson.Field
|
||||
raw string
|
||||
ExtraFields map[string]apijson.Field
|
||||
}
|
||||
|
||||
func (r *ConfigProviderOptions) UnmarshalJSON(data []byte) (err error) {
|
||||
return apijson.UnmarshalRoot(data, r)
|
||||
}
|
||||
|
||||
func (r configProviderOptionsJSON) RawJSON() string {
|
||||
return r.raw
|
||||
}
|
||||
|
||||
// Control sharing behavior:'manual' allows manual sharing via commands, 'auto'
|
||||
// enables automatic sharing, 'disabled' disables all sharing
|
||||
type ConfigShare string
|
||||
|
||||
@@ -55,6 +55,7 @@ type EventListResponse struct {
|
||||
// [EventListResponseEventMessageUpdatedProperties],
|
||||
// [EventListResponseEventMessageRemovedProperties],
|
||||
// [EventListResponseEventMessagePartUpdatedProperties],
|
||||
// [EventListResponseEventMessagePartRemovedProperties],
|
||||
// [EventListResponseEventStorageWriteProperties],
|
||||
// [EventListResponseEventSessionUpdatedProperties],
|
||||
// [EventListResponseEventSessionDeletedProperties],
|
||||
@@ -99,6 +100,7 @@ func (r *EventListResponse) UnmarshalJSON(data []byte) (err error) {
|
||||
// [EventListResponseEventInstallationUpdated],
|
||||
// [EventListResponseEventMessageUpdated], [EventListResponseEventMessageRemoved],
|
||||
// [EventListResponseEventMessagePartUpdated],
|
||||
// [EventListResponseEventMessagePartRemoved],
|
||||
// [EventListResponseEventStorageWrite], [EventListResponseEventSessionUpdated],
|
||||
// [EventListResponseEventSessionDeleted], [EventListResponseEventSessionIdle],
|
||||
// [EventListResponseEventSessionError],
|
||||
@@ -113,6 +115,7 @@ func (r EventListResponse) AsUnion() EventListResponseUnion {
|
||||
// [EventListResponseEventInstallationUpdated],
|
||||
// [EventListResponseEventMessageUpdated], [EventListResponseEventMessageRemoved],
|
||||
// [EventListResponseEventMessagePartUpdated],
|
||||
// [EventListResponseEventMessagePartRemoved],
|
||||
// [EventListResponseEventStorageWrite], [EventListResponseEventSessionUpdated],
|
||||
// [EventListResponseEventSessionDeleted], [EventListResponseEventSessionIdle],
|
||||
// [EventListResponseEventSessionError], [EventListResponseEventFileWatcherUpdated]
|
||||
@@ -160,6 +163,11 @@ func init() {
|
||||
Type: reflect.TypeOf(EventListResponseEventMessagePartUpdated{}),
|
||||
DiscriminatorValue: "message.part.updated",
|
||||
},
|
||||
apijson.UnionVariant{
|
||||
TypeFilter: gjson.JSON,
|
||||
Type: reflect.TypeOf(EventListResponseEventMessagePartRemoved{}),
|
||||
DiscriminatorValue: "message.part.removed",
|
||||
},
|
||||
apijson.UnionVariant{
|
||||
TypeFilter: gjson.JSON,
|
||||
Type: reflect.TypeOf(EventListResponseEventStorageWrite{}),
|
||||
@@ -651,6 +659,68 @@ func (r EventListResponseEventMessagePartUpdatedType) IsKnown() bool {
|
||||
return false
|
||||
}
|
||||
|
||||
type EventListResponseEventMessagePartRemoved struct {
|
||||
Properties EventListResponseEventMessagePartRemovedProperties `json:"properties,required"`
|
||||
Type EventListResponseEventMessagePartRemovedType `json:"type,required"`
|
||||
JSON eventListResponseEventMessagePartRemovedJSON `json:"-"`
|
||||
}
|
||||
|
||||
// eventListResponseEventMessagePartRemovedJSON contains the JSON metadata for the
|
||||
// struct [EventListResponseEventMessagePartRemoved]
|
||||
type eventListResponseEventMessagePartRemovedJSON struct {
|
||||
Properties apijson.Field
|
||||
Type apijson.Field
|
||||
raw string
|
||||
ExtraFields map[string]apijson.Field
|
||||
}
|
||||
|
||||
func (r *EventListResponseEventMessagePartRemoved) UnmarshalJSON(data []byte) (err error) {
|
||||
return apijson.UnmarshalRoot(data, r)
|
||||
}
|
||||
|
||||
func (r eventListResponseEventMessagePartRemovedJSON) RawJSON() string {
|
||||
return r.raw
|
||||
}
|
||||
|
||||
func (r EventListResponseEventMessagePartRemoved) implementsEventListResponse() {}
|
||||
|
||||
type EventListResponseEventMessagePartRemovedProperties struct {
|
||||
MessageID string `json:"messageID,required"`
|
||||
PartID string `json:"partID,required"`
|
||||
JSON eventListResponseEventMessagePartRemovedPropertiesJSON `json:"-"`
|
||||
}
|
||||
|
||||
// eventListResponseEventMessagePartRemovedPropertiesJSON contains the JSON
|
||||
// metadata for the struct [EventListResponseEventMessagePartRemovedProperties]
|
||||
type eventListResponseEventMessagePartRemovedPropertiesJSON struct {
|
||||
MessageID apijson.Field
|
||||
PartID apijson.Field
|
||||
raw string
|
||||
ExtraFields map[string]apijson.Field
|
||||
}
|
||||
|
||||
func (r *EventListResponseEventMessagePartRemovedProperties) UnmarshalJSON(data []byte) (err error) {
|
||||
return apijson.UnmarshalRoot(data, r)
|
||||
}
|
||||
|
||||
func (r eventListResponseEventMessagePartRemovedPropertiesJSON) RawJSON() string {
|
||||
return r.raw
|
||||
}
|
||||
|
||||
type EventListResponseEventMessagePartRemovedType string
|
||||
|
||||
const (
|
||||
EventListResponseEventMessagePartRemovedTypeMessagePartRemoved EventListResponseEventMessagePartRemovedType = "message.part.removed"
|
||||
)
|
||||
|
||||
func (r EventListResponseEventMessagePartRemovedType) IsKnown() bool {
|
||||
switch r {
|
||||
case EventListResponseEventMessagePartRemovedTypeMessagePartRemoved:
|
||||
return true
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
type EventListResponseEventStorageWrite struct {
|
||||
Properties EventListResponseEventStorageWriteProperties `json:"properties,required"`
|
||||
Type EventListResponseEventStorageWriteType `json:"type,required"`
|
||||
@@ -1236,6 +1306,7 @@ const (
|
||||
EventListResponseTypeMessageUpdated EventListResponseType = "message.updated"
|
||||
EventListResponseTypeMessageRemoved EventListResponseType = "message.removed"
|
||||
EventListResponseTypeMessagePartUpdated EventListResponseType = "message.part.updated"
|
||||
EventListResponseTypeMessagePartRemoved EventListResponseType = "message.part.removed"
|
||||
EventListResponseTypeStorageWrite EventListResponseType = "storage.write"
|
||||
EventListResponseTypeSessionUpdated EventListResponseType = "session.updated"
|
||||
EventListResponseTypeSessionDeleted EventListResponseType = "session.deleted"
|
||||
@@ -1247,7 +1318,7 @@ const (
|
||||
|
||||
func (r EventListResponseType) IsKnown() bool {
|
||||
switch r {
|
||||
case EventListResponseTypeLspClientDiagnostics, EventListResponseTypePermissionUpdated, EventListResponseTypeFileEdited, EventListResponseTypeInstallationUpdated, EventListResponseTypeMessageUpdated, EventListResponseTypeMessageRemoved, EventListResponseTypeMessagePartUpdated, EventListResponseTypeStorageWrite, EventListResponseTypeSessionUpdated, EventListResponseTypeSessionDeleted, EventListResponseTypeSessionIdle, EventListResponseTypeSessionError, EventListResponseTypeFileWatcherUpdated, EventListResponseTypeIdeInstalled:
|
||||
case EventListResponseTypeLspClientDiagnostics, EventListResponseTypePermissionUpdated, EventListResponseTypeFileEdited, EventListResponseTypeInstallationUpdated, EventListResponseTypeMessageUpdated, EventListResponseTypeMessageRemoved, EventListResponseTypeMessagePartUpdated, EventListResponseTypeMessagePartRemoved, EventListResponseTypeStorageWrite, EventListResponseTypeSessionUpdated, EventListResponseTypeSessionDeleted, EventListResponseTypeSessionIdle, EventListResponseTypeSessionError, EventListResponseTypeFileWatcherUpdated, EventListResponseTypeIdeInstalled:
|
||||
return true
|
||||
}
|
||||
return false
|
||||
|
||||
@@ -175,6 +175,7 @@ func (r *SessionService) Unshare(ctx context.Context, id string, opts ...option.
|
||||
type AssistantMessage struct {
|
||||
ID string `json:"id,required"`
|
||||
Cost float64 `json:"cost,required"`
|
||||
Mode string `json:"mode,required"`
|
||||
ModelID string `json:"modelID,required"`
|
||||
Path AssistantMessagePath `json:"path,required"`
|
||||
ProviderID string `json:"providerID,required"`
|
||||
@@ -193,6 +194,7 @@ type AssistantMessage struct {
|
||||
type assistantMessageJSON struct {
|
||||
ID apijson.Field
|
||||
Cost apijson.Field
|
||||
Mode apijson.Field
|
||||
ModelID apijson.Field
|
||||
Path apijson.Field
|
||||
ProviderID apijson.Field
|
||||
@@ -735,6 +737,7 @@ type Message struct {
|
||||
Cost float64 `json:"cost"`
|
||||
// This field can have the runtime type of [AssistantMessageError].
|
||||
Error interface{} `json:"error"`
|
||||
Mode string `json:"mode"`
|
||||
ModelID string `json:"modelID"`
|
||||
// This field can have the runtime type of [AssistantMessagePath].
|
||||
Path interface{} `json:"path"`
|
||||
@@ -756,6 +759,7 @@ type messageJSON struct {
|
||||
Time apijson.Field
|
||||
Cost apijson.Field
|
||||
Error apijson.Field
|
||||
Mode apijson.Field
|
||||
ModelID apijson.Field
|
||||
Path apijson.Field
|
||||
ProviderID apijson.Field
|
||||
@@ -832,6 +836,9 @@ type Part struct {
|
||||
CallID string `json:"callID"`
|
||||
Cost float64 `json:"cost"`
|
||||
Filename string `json:"filename"`
|
||||
// This field can have the runtime type of [[]string].
|
||||
Files interface{} `json:"files"`
|
||||
Hash string `json:"hash"`
|
||||
Mime string `json:"mime"`
|
||||
Snapshot string `json:"snapshot"`
|
||||
Source FilePartSource `json:"source"`
|
||||
@@ -858,6 +865,8 @@ type partJSON struct {
|
||||
CallID apijson.Field
|
||||
Cost apijson.Field
|
||||
Filename apijson.Field
|
||||
Files apijson.Field
|
||||
Hash apijson.Field
|
||||
Mime apijson.Field
|
||||
Snapshot apijson.Field
|
||||
Source apijson.Field
|
||||
@@ -889,13 +898,13 @@ func (r *Part) UnmarshalJSON(data []byte) (err error) {
|
||||
// for more type safety.
|
||||
//
|
||||
// Possible runtime types of the union are [TextPart], [FilePart], [ToolPart],
|
||||
// [StepStartPart], [StepFinishPart], [SnapshotPart].
|
||||
// [StepStartPart], [StepFinishPart], [SnapshotPart], [PartPatchPart].
|
||||
func (r Part) AsUnion() PartUnion {
|
||||
return r.union
|
||||
}
|
||||
|
||||
// Union satisfied by [TextPart], [FilePart], [ToolPart], [StepStartPart],
|
||||
// [StepFinishPart] or [SnapshotPart].
|
||||
// [StepFinishPart], [SnapshotPart] or [PartPatchPart].
|
||||
type PartUnion interface {
|
||||
implementsPart()
|
||||
}
|
||||
@@ -934,9 +943,60 @@ func init() {
|
||||
Type: reflect.TypeOf(SnapshotPart{}),
|
||||
DiscriminatorValue: "snapshot",
|
||||
},
|
||||
apijson.UnionVariant{
|
||||
TypeFilter: gjson.JSON,
|
||||
Type: reflect.TypeOf(PartPatchPart{}),
|
||||
DiscriminatorValue: "patch",
|
||||
},
|
||||
)
|
||||
}
|
||||
|
||||
type PartPatchPart struct {
|
||||
ID string `json:"id,required"`
|
||||
Files []string `json:"files,required"`
|
||||
Hash string `json:"hash,required"`
|
||||
MessageID string `json:"messageID,required"`
|
||||
SessionID string `json:"sessionID,required"`
|
||||
Type PartPatchPartType `json:"type,required"`
|
||||
JSON partPatchPartJSON `json:"-"`
|
||||
}
|
||||
|
||||
// partPatchPartJSON contains the JSON metadata for the struct [PartPatchPart]
|
||||
type partPatchPartJSON struct {
|
||||
ID apijson.Field
|
||||
Files apijson.Field
|
||||
Hash apijson.Field
|
||||
MessageID apijson.Field
|
||||
SessionID apijson.Field
|
||||
Type apijson.Field
|
||||
raw string
|
||||
ExtraFields map[string]apijson.Field
|
||||
}
|
||||
|
||||
func (r *PartPatchPart) UnmarshalJSON(data []byte) (err error) {
|
||||
return apijson.UnmarshalRoot(data, r)
|
||||
}
|
||||
|
||||
func (r partPatchPartJSON) RawJSON() string {
|
||||
return r.raw
|
||||
}
|
||||
|
||||
func (r PartPatchPart) implementsPart() {}
|
||||
|
||||
type PartPatchPartType string
|
||||
|
||||
const (
|
||||
PartPatchPartTypePatch PartPatchPartType = "patch"
|
||||
)
|
||||
|
||||
func (r PartPatchPartType) IsKnown() bool {
|
||||
switch r {
|
||||
case PartPatchPartTypePatch:
|
||||
return true
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
type PartType string
|
||||
|
||||
const (
|
||||
@@ -946,11 +1006,12 @@ const (
|
||||
PartTypeStepStart PartType = "step-start"
|
||||
PartTypeStepFinish PartType = "step-finish"
|
||||
PartTypeSnapshot PartType = "snapshot"
|
||||
PartTypePatch PartType = "patch"
|
||||
)
|
||||
|
||||
func (r PartType) IsKnown() bool {
|
||||
switch r {
|
||||
case PartTypeText, PartTypeFile, PartTypeTool, PartTypeStepStart, PartTypeStepFinish, PartTypeSnapshot:
|
||||
case PartTypeText, PartTypeFile, PartTypeTool, PartTypeStepStart, PartTypeStepFinish, PartTypeSnapshot, PartTypePatch:
|
||||
return true
|
||||
}
|
||||
return false
|
||||
|
||||
Reference in New Issue
Block a user