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