Compare commits

..
Author SHA1 Message Date
Dax Raad 7bf95ba7bf Snapshot release v0.0.0-202509010531 2025-09-01 01:33:09 -04:00
Dax Raad e2cbe4b961 morelog 2025-09-01 01:31:41 -04:00
Dax Raad 9ec65c5e4b Merge branch 'dev' into project 2025-08-31 20:32:44 -04:00
Dax Raad 55cfacc6f4 core: sync updates across opencode, sdk, tui, and plugin components 2025-08-31 20:19:30 -04:00
Dax Raad b51975fd67 sync 2025-08-31 19:43:11 -04:00
Dax Raad ce1b5ee496 sync 2025-08-31 02:32:34 -04:00
Dax Raad 647671dbe6 sync 2025-08-31 02:16:43 -04:00
Dax Raad 3977b9b8c9 sync 2025-08-31 00:04:22 -04:00
Dax Raad 8905b31bdb sync 2025-08-31 00:03:16 -04:00
Dax Raad 46af0aca8e sync 2025-08-30 15:23:42 -04:00
Dax Raad 11afe56f63 Merge branch 'dev' into project 2025-08-30 15:22:48 -04:00
Dax Raad 5288e9cb86 fix 2025-08-23 16:27:53 -04:00
Dax Raad 61468546be Merge branch 'dev' into project 2025-08-23 16:26:45 -04:00
Dax Raad aebcc8ac32 update copilot prompt 2025-08-12 20:00:39 -04:00
Dax Raad 368354779b remove debug console.log from session 2025-08-12 19:00:54 -04:00
Dax Raad ca0c1632ea Add export command to CLI tool 2025-08-12 19:00:01 -04:00
Dax Raad 6498a4624c Merge branch 'dev' into project 2025-08-12 18:52:30 -04:00
Dax Raad 806d8a84b4 sync 2025-08-07 18:46:40 -04:00
Dax Raad 961e605c73 sync 2025-08-07 18:17:01 -04:00
Dax Raad 041d463210 Merge branch 'dev' into project 2025-08-07 18:16:36 -04:00
Dax Raad f82f29cd24 progress 2025-08-07 15:01:44 -04:00
Dax Raad 6015a47dae sync 2025-08-07 00:44:15 -04:00
Dax Raad 6c3c7ceb2f sync 2025-08-07 00:43:12 -04:00
Dax Raad 1fb54efdd2 sync 2025-08-07 00:41:50 -04:00
Dax Raad d45d5d664c progress 2025-08-06 23:15:19 -04:00
Dax Raad 323ce486a5 sync 2025-08-06 23:15:19 -04:00
Dax Raad 390b660c81 progress 2025-08-06 23:15:19 -04:00
46 changed files with 296 additions and 596 deletions
-1
View File
@@ -65,4 +65,3 @@
| 2025-08-29 | 256,045 (+3,249) | 211,075 (+5,833) | 467,120 (+9,082) |
| 2025-08-30 | 258,863 (+2,818) | 212,397 (+1,322) | 471,260 (+4,140) |
| 2025-08-31 | 262,004 (+3,141) | 213,944 (+1,547) | 475,948 (+4,688) |
| 2025-09-01 | 265,359 (+3,355) | 215,115 (+1,171) | 480,474 (+4,526) |
+1 -1
View File
@@ -6,7 +6,7 @@
"dev:remote": "VITE_AUTH_URL=https://auth.dev.opencode.ai bun sst shell --stage=dev bun dev",
"build": "vinxi build",
"start": "vinxi start",
"version": "0.6.0"
"version": "0.5.29"
},
"dependencies": {
"@ibm/plex": "6.4.1",
+1 -1
View File
@@ -52,7 +52,7 @@ export const getActor = query(async (): Promise<Actor.Info> => {
}
}
const workspaceHint = splits[1]
const accounts = Object.keys(auth.data.account ?? {})
const accounts = Object.keys(auth.data.account)
const result = await Database.transaction(async (tx) => {
return await tx
.select({
+1 -3
View File
@@ -20,6 +20,4 @@ export default createHandler(() => (
</html>
)}
/>
), {
mode: "sync",
})
))
+2 -6
View File
@@ -1,13 +1,9 @@
import type { APIEvent } from "@solidjs/start/server"
import { Resource } from "@opencode/cloud-resource"
import { json } from "@solidjs/router"
import { Database } from "@opencode/cloud-core/drizzle/index.js"
import { UserTable } from "@opencode/cloud-core/schema/user.sql.js"
export async function GET(evt: APIEvent) {
return json({
data: await Database.use(async (tx) => {
const result = await tx.$count(UserTable)
return result
}),
data: Resource.Database.host,
})
}
+4 -4
View File
@@ -30,9 +30,7 @@ const logout = action(async () => {
})
export default function WorkspaceLayout(props: RouteSectionProps) {
const userInfo = createAsync(() => getUserInfo(), {
deferStream: true,
})
const userInfo = createAsync(() => getUserInfo())
return (
<main data-page="workspace">
<header data-component="workspace-header">
@@ -42,7 +40,9 @@ export default function WorkspaceLayout(props: RouteSectionProps) {
</a>
</div>
<div data-slot="header-actions">
<span>{userInfo()?.user.email}</span>
{userInfo() &&
<span>{userInfo()!.user.email}</span>
}
<form action={logout} method="post">
<button type="submit" formaction={logout}>Logout</button>
</form>
+4 -7
View File
@@ -63,14 +63,13 @@ const createPortalUrl = action(async (returnUrl: string) => {
return withActor(() => Billing.generatePortalUrl({ returnUrl }))
}, "portalUrl")
export default function () {
export default function() {
const actor = createAsync(() => getActor())
/////////////////
// Keys section
/////////////////
const keys = createAsync(() => listKeys(), {
deferStream: true,
})
const keys = createAsync(() => listKeys())
const createKeyAction = useAction(createKey)
const removeKeyAction = useAction(removeKey)
const createKeySubmission = useSubmission(createKey)
@@ -158,9 +157,7 @@ export default function () {
/////////////////
// Billing section
/////////////////
const billingInfo = createAsync(() => getBillingInfo(), {
deferStream: true,
})
const billingInfo = createAsync(() => getBillingInfo())
const createCheckoutUrlAction = useAction(createCheckoutUrl)
const createCheckoutUrlSubmission = useSubmission(createCheckoutUrl)
+1 -1
View File
@@ -1,7 +1,7 @@
{
"$schema": "https://json.schemastore.org/package.json",
"name": "@opencode/cloud-core",
"version": "0.6.0",
"version": "0.5.29",
"private": true,
"type": "module",
"dependencies": {
+2 -2
View File
@@ -15,12 +15,12 @@ const init = () => {
ssl: {
rejectUnauthorized: false,
},
max: 6,
max: 1,
})
return drizzle(client, {})
}
const createClient = init
const createClient = "NODE_ENV" in process.env ? memo(init) : init
import { PgTransaction, type PgTransactionConfig } from "drizzle-orm/pg-core"
import type { ExtractTablesWithRelations } from "drizzle-orm"
+1 -1
View File
@@ -1,6 +1,6 @@
{
"name": "@opencode/cloud-function",
"version": "0.6.0",
"version": "0.5.29",
"$schema": "https://json.schemastore.org/package.json",
"private": true,
"type": "module",
+1 -1
View File
@@ -13,7 +13,7 @@ export const database = new sst.Linkable("Database", {
database: "postgres",
username: DATABASE_USERNAME.value,
password: DATABASE_PASSWORD.value,
port: 6432,
port: 5432,
},
})
+1 -1
View File
@@ -1,6 +1,6 @@
{
"name": "@opencode/function",
"version": "0.6.0",
"version": "0.5.29",
"$schema": "https://json.schemastore.org/package.json",
"private": true,
"type": "module",
+1 -1
View File
@@ -1,6 +1,6 @@
{
"$schema": "https://json.schemastore.org/package.json",
"version": "0.6.0",
"version": "0.5.29",
"name": "opencode",
"type": "module",
"private": true,
+6 -32
View File
@@ -10,7 +10,6 @@ import { bootstrap } from "../bootstrap"
import { MessageV2 } from "../../session/message-v2"
import { Identifier } from "../../id/id"
import { Agent } from "../../agent/agent"
import { Command } from "../../command"
const TOOL: Record<string, [string, string]> = {
todowrite: ["Todo", UI.Style.TEXT_WARNING_BOLD],
@@ -36,10 +35,6 @@ export const RunCommand = cmd({
array: true,
default: [],
})
.option("command", {
describe: "the command to run, use message for args",
type: "string",
})
.option("continue", {
alias: ["c"],
describe: "continue the last session",
@@ -69,19 +64,12 @@ export const RunCommand = cmd({
if (!process.stdin.isTTY) message += "\n" + (await Bun.stdin.text())
if (message.trim().length === 0 && !args.command) {
UI.error("You must provide a message or a command")
if (message.trim().length === 0) {
UI.error("Message cannot be empty")
return
}
await bootstrap(process.cwd(), async () => {
if (args.command) {
const exists = await Command.get(args.command)
if (!exists) {
UI.error(`Command "${args.command}" not found`)
return
}
}
const session = await (async () => {
if (args.continue) {
const it = Session.list()
@@ -184,26 +172,12 @@ export const RunCommand = cmd({
UI.error(err)
})
if (args.command) {
await Session.command({
messageID: Identifier.ascending("message"),
sessionID: session.id,
agent: agent.name,
model: providerID + "/" + modelID,
command: args.command,
arguments: message,
})
return
}
const messageID = Identifier.ascending("message")
const result = await Session.prompt({
const result = await Session.chat({
sessionID: session.id,
messageID,
model: {
providerID,
modelID,
},
providerID,
modelID,
agent: agent.name,
parts: [
{
@@ -216,7 +190,7 @@ export const RunCommand = cmd({
const isPiped = !process.stdout.isTTY
if (isPiped) {
const match = result.parts.findLast((x: any) => x.type === "text") as any
const match = result.parts.findLast((x) => x.type === "text")
if (match) process.stdout.write(UI.markdown(match.text))
if (errorMsg) process.stdout.write(errorMsg)
}
+1 -1
View File
@@ -193,7 +193,7 @@ export namespace LSPServer {
}
export const Gopls: Info = {
id: "gopls",
id: "golang",
root: async (file) => {
const work = await NearestRoot(["go.work"])(file)
if (work) return work
+1 -8
View File
@@ -153,10 +153,7 @@ export namespace Provider {
options: Record<string, any>
}
} = {}
const models = new Map<
string,
{ providerID: string; modelID: string; info: ModelsDev.Model; language: LanguageModel }
>()
const models = new Map<string, { info: ModelsDev.Model; language: LanguageModel }>()
const sdk = new Map<string, SDK>()
log.info("init")
@@ -365,14 +362,10 @@ export namespace Provider {
const language = provider.getModel ? await provider.getModel(sdk, modelID) : sdk.languageModel(modelID)
log.info("found", { providerID, modelID })
s.models.set(key, {
providerID,
modelID,
info,
language,
})
return {
modelID,
providerID,
info,
language,
}
+1 -1
View File
@@ -30,7 +30,7 @@ export const ProjectRoute = new Hono()
"/current",
describeRoute({
description: "Get the current project",
operationId: "project.current",
operationId: "butt.current",
responses: {
200: {
description: "Current project",
+3 -6
View File
@@ -53,9 +53,6 @@ export namespace Server {
const app = new Hono()
export const App = app
.onError((err, c) => {
log.error("failed", {
error: err,
})
if (err instanceof NamedError) {
return c.json(err.toObject(), {
status: 400,
@@ -609,7 +606,7 @@ export namespace Server {
"/session/:id/message",
describeRoute({
description: "Create and send a new message to a session",
operationId: "session.prompt",
operationId: "session.chat",
responses: {
200: {
description: "Created message",
@@ -632,11 +629,11 @@ export namespace Server {
id: z.string().openapi({ description: "Session ID" }),
}),
),
zValidator("json", Session.PromptInput.omit({ sessionID: true })),
zValidator("json", Session.ChatInput.omit({ sessionID: true })),
async (c) => {
const sessionID = c.req.valid("param").id
const body = c.req.valid("json")
const msg = await Session.prompt({ ...body, sessionID })
const msg = await Session.chat({ ...body, sessionID })
return c.json(msg)
},
)
+46 -61
View File
@@ -364,15 +364,11 @@ export namespace Session {
return part
}
export const PromptInput = z.object({
export const ChatInput = z.object({
sessionID: Identifier.schema("session"),
messageID: Identifier.schema("message").optional(),
model: z
.object({
providerID: z.string(),
modelID: z.string(),
})
.optional(),
providerID: z.string(),
modelID: z.string(),
agent: z.string().optional(),
system: z.string().optional(),
tools: z.record(z.boolean()).optional(),
@@ -411,10 +407,10 @@ export namespace Session {
]),
),
})
export type ChatInput = z.infer<typeof PromptInput>
export type ChatInput = z.infer<typeof ChatInput>
export async function prompt(
input: z.infer<typeof PromptInput>,
export async function chat(
input: z.infer<typeof ChatInput>,
): Promise<{ info: MessageV2.Assistant; parts: MessageV2.Part[] }> {
const l = log.clone().tag("session", input.sessionID)
l.info("chatting")
@@ -656,16 +652,7 @@ export namespace Session {
})
}
const agent = await Agent.get(inputAgent)
const model = await (async () => {
if (input.model) {
return input.model
}
if (agent.model) {
return agent.model
}
return Provider.defaultModel()
})().then((x) => Provider.getModel(x.providerID, x.modelID))
const model = await Provider.getModel(input.providerID, input.modelID)
let msgs = await messages(input.sessionID)
const previous = msgs.filter((x) => x.info.role === "assistant").at(-1)?.info as MessageV2.Assistant
@@ -680,10 +667,10 @@ export namespace Session {
await summarize({
sessionID: input.sessionID,
providerID: model.providerID,
modelID: model.info.id,
providerID: input.providerID,
modelID: input.modelID,
})
return prompt(input)
return chat(input)
}
}
using abort = lock(input.sessionID)
@@ -692,17 +679,17 @@ export namespace Session {
if (lastSummary) msgs = msgs.filter((msg) => msg.info.id >= lastSummary.info.id)
if (msgs.filter((m) => m.info.role === "user").length === 1 && !session.parentID && isDefaultTitle(session.title)) {
const small = (await Provider.getSmallModel(model.providerID)) ?? model
const small = (await Provider.getSmallModel(input.providerID)) ?? model
generateText({
maxOutputTokens: small.info.reasoning ? 1024 : 20,
providerOptions: {
[model.providerID]: {
[input.providerID]: {
...small.info.options,
...ProviderTransform.options(small.providerID, small.modelID, input.sessionID),
...ProviderTransform.options(input.providerID, small.info.id, input.sessionID),
},
},
messages: [
...SystemPrompt.title(model.providerID).map(
...SystemPrompt.title(input.providerID).map(
(x): ModelMessage => ({
role: "system",
content: x,
@@ -737,6 +724,7 @@ export namespace Session {
})
}
const agent = await Agent.get(inputAgent)
if (agent.name === "plan") {
msgs.at(-1)?.parts.push({
id: Identifier.ascending("part"),
@@ -759,12 +747,12 @@ export namespace Session {
synthetic: true,
})
}
let system = SystemPrompt.header(model.providerID)
let system = SystemPrompt.header(input.providerID)
system.push(
...(() => {
if (input.system) return [input.system]
if (agent.prompt) return [agent.prompt]
return SystemPrompt.provider(model.modelID)
return SystemPrompt.provider(input.modelID)
})(),
)
system.push(...(await SystemPrompt.environment()))
@@ -789,8 +777,8 @@ export namespace Session {
reasoning: 0,
cache: { read: 0, write: 0 },
},
modelID: model.modelID,
providerID: model.providerID,
modelID: input.modelID,
providerID: input.providerID,
time: {
created: Date.now(),
},
@@ -808,10 +796,10 @@ export namespace Session {
const enabledTools = pipe(
agent.tools,
mergeDeep(await ToolRegistry.enabled(model.providerID, model.modelID, agent)),
mergeDeep(await ToolRegistry.enabled(input.providerID, input.modelID, agent)),
mergeDeep(input.tools ?? {}),
)
for (const item of await ToolRegistry.tools(model.providerID, model.modelID)) {
for (const item of await ToolRegistry.tools(input.providerID, input.modelID)) {
if (Wildcard.all(item.id, enabledTools) === false) continue
tools[item.id] = tool({
id: item.id as any,
@@ -921,16 +909,16 @@ export namespace Session {
"chat.params",
{
model: model.info,
provider: await Provider.getProvider(model.providerID),
provider: await Provider.getProvider(input.providerID),
message: userMsg,
},
{
temperature: model.info.temperature
? (agent.temperature ?? ProviderTransform.temperature(model.providerID, model.modelID))
? (agent.temperature ?? ProviderTransform.temperature(input.providerID, input.modelID))
: undefined,
topP: agent.topP ?? ProviderTransform.topP(model.providerID, model.modelID),
topP: agent.topP ?? ProviderTransform.topP(input.providerID, input.modelID),
options: {
...ProviderTransform.options(model.providerID, model.modelID, input.sessionID),
...ProviderTransform.options(input.providerID, input.modelID, input.sessionID),
...model.info.options,
...agent.options,
},
@@ -974,8 +962,8 @@ export namespace Session {
reasoning: 0,
cache: { read: 0, write: 0 },
},
modelID: model.modelID,
providerID: model.providerID,
modelID: input.modelID,
providerID: input.providerID,
mode: inputAgent,
time: {
created: Date.now(),
@@ -999,7 +987,7 @@ export namespace Session {
}
},
headers:
model.providerID === "opencode"
input.providerID === "opencode"
? {
"x-opencode-session": input.sessionID,
"x-opencode-request": userMsg.id,
@@ -1022,7 +1010,7 @@ export namespace Session {
return false
},
providerOptions: {
[model.providerID]: params.options,
[input.providerID]: params.options,
},
temperature: params.temperature,
topP: params.topP,
@@ -1043,7 +1031,7 @@ export namespace Session {
async transformParams(args) {
if (args.type === "stream") {
// @ts-expect-error
args.params.prompt = ProviderTransform.message(args.params.prompt, model.providerID, model.modelID)
args.params.prompt = ProviderTransform.message(args.params.prompt, input.providerID, input.modelID)
}
return args.params
},
@@ -1056,7 +1044,7 @@ export namespace Session {
const unprocessed = queued.find((x) => !x.processed)
if (unprocessed) {
unprocessed.processed = true
return prompt(unprocessed.input)
return chat(unprocessed.input)
}
for (const item of queued) {
item.callback(result)
@@ -1232,9 +1220,16 @@ export namespace Session {
const fileRegex = /@([^\s]+)/g
export async function command(input: CommandInput) {
log.info("command", input)
const command = await Command.get(input.command)
const agent = command.agent ?? input.agent ?? "build"
const fmtModel = (model: { providerID: string; modelID: string }) => `${model.providerID}/${model.modelID}`
const model =
command.model ??
(command.agent && (await Agent.get(command.agent).then((x) => (x.model ? fmtModel(x.model) : undefined)))) ??
input.model ??
(input.agent && (await Agent.get(input.agent).then((x) => (x.model ? fmtModel(x.model) : undefined)))) ??
fmtModel(await Provider.defaultModel())
let template = command.template.replace("$ARGUMENTS", input.arguments)
@@ -1278,18 +1273,10 @@ export namespace Session {
})
}
return prompt({
return chat({
sessionID: input.sessionID,
messageID: input.messageID,
model: (() => {
if (input.model) {
return Provider.parseModel(input.model)
}
if (command.model) {
return Provider.parseModel(command.model)
}
return undefined
})(),
...Provider.parseModel(model!),
agent,
parts,
})
@@ -1656,7 +1643,7 @@ export namespace Session {
const filtered = msgs.filter((msg) => !lastSummary || msg.info.id >= lastSummary.info.id)
const model = await Provider.getModel(input.providerID, input.modelID)
const system = [
...SystemPrompt.summarize(model.providerID),
...SystemPrompt.summarize(input.providerID),
...(await SystemPrompt.environment()),
...(await SystemPrompt.custom()),
]
@@ -1674,7 +1661,7 @@ export namespace Session {
summary: true,
cost: 0,
modelID: input.modelID,
providerID: model.providerID,
providerID: input.providerID,
tokens: {
input: 0,
output: 0,
@@ -1783,13 +1770,11 @@ export namespace Session {
providerID: string
messageID: string
}) {
await Session.prompt({
await Session.chat({
sessionID: input.sessionID,
messageID: input.messageID,
model: {
providerID: input.providerID,
modelID: input.modelID,
},
providerID: input.providerID,
modelID: input.modelID,
parts: [
{
id: Identifier.ascending("part"),
-1
View File
@@ -30,7 +30,6 @@ export namespace Storage {
if (worktree) break
}
if (!worktree) continue
if (!(await fs.exists(worktree))) continue
const [id] = await $`git rev-list --max-parents=0 --all`
.quiet()
.nothrow()
+5 -7
View File
@@ -51,13 +51,11 @@ export const TaskTool = Tool.define("task", async () => {
ctx.abort.addEventListener("abort", () => {
Session.abort(session.id)
})
const result = await Session.prompt({
const result = await Session.chat({
messageID,
sessionID: session.id,
model: {
modelID: model.modelID,
providerID: model.providerID,
},
modelID: model.modelID,
providerID: model.providerID,
agent: agent.name,
tools: {
todowrite: false,
@@ -77,9 +75,9 @@ export const TaskTool = Tool.define("task", async () => {
return {
title: params.description,
metadata: {
summary: result.parts.filter((x: any) => x.type === "tool"),
summary: result.parts.filter((x) => x.type === "tool"),
},
output: (result.parts.findLast((x: any) => x.type === "text") as any)?.text ?? "",
output: result.parts.findLast((x) => x.type === "text")?.text ?? "",
}
},
}
+1 -1
View File
@@ -1,7 +1,7 @@
{
"$schema": "https://json.schemastore.org/package.json",
"name": "@opencode-ai/plugin",
"version": "0.6.0",
"version": "0.5.29",
"type": "module",
"scripts": {
"typecheck": "tsc --noEmit"
+2 -8
View File
@@ -1,15 +1,9 @@
import { Plugin } from "./index"
export const ExamplePlugin: Plugin = async ({
client: _client,
$: _shell,
project: _project,
directory: _directory,
worktree: _worktree,
}) => {
export const ExamplePlugin: Plugin = async ({ client, $ }) => {
return {
permission: {},
async "chat.params"(_input, output) {
async "chat.params"(input, output) {
output.topP = 1
},
}
@@ -1,3 +1,3 @@
{
".": "0.8.0"
".": "0.5.0"
}
+3 -3
View File
@@ -1,4 +1,4 @@
configured_endpoints: 43
openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/opencode%2Fopencode-97b61518d8666ea7cb310af04248e00bcf8dc9753ba3c7e84471df72b3232004.yml
openapi_spec_hash: a3500531973ad999c350b87c21aa3ab8
config_hash: 026ef000d34bf2f930e7b41e77d2d3ff
openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/opencode%2Fopencode-24d6bfcc66bba2e3a826fdad7e48a474c5aa9193a6bb89dc8ab1feb1f3d9bf72.yml
openapi_spec_hash: db8b553192d9027e1f9254096406cfc2
config_hash: 1b0d220e033fe9f683abf7048e7ad076
-24
View File
@@ -1,29 +1,5 @@
# Changelog
## 0.8.0 (2025-09-01)
Full Changelog: [v0.7.0...v0.8.0](https://github.com/sst/opencode-sdk-go/compare/v0.7.0...v0.8.0)
### Features
* **api:** api update ([ae87a71](https://github.com/sst/opencode-sdk-go/commit/ae87a71949994590ace8285a39f0991ef34b664d))
## 0.7.0 (2025-09-01)
Full Changelog: [v0.6.0...v0.7.0](https://github.com/sst/opencode-sdk-go/compare/v0.6.0...v0.7.0)
### Features
* **api:** api update ([64bb1b1](https://github.com/sst/opencode-sdk-go/commit/64bb1b1ee0cbe153abc6fb7bd9703b47911724d4))
## 0.6.0 (2025-09-01)
Full Changelog: [v0.5.0...v0.6.0](https://github.com/sst/opencode-sdk-go/compare/v0.5.0...v0.6.0)
### Features
* **api:** api update ([928e384](https://github.com/sst/opencode-sdk-go/commit/928e3843355f96899f046f002b84372281dad0c8))
## 0.5.0 (2025-08-31)
Full Changelog: [v0.4.0...v0.5.0](https://github.com/sst/opencode-sdk-go/compare/v0.4.0...v0.5.0)
+1 -1
View File
@@ -24,7 +24,7 @@ Or to pin the version:
<!-- x-release-please-start-version -->
```sh
go get -u 'github.com/sst/opencode-sdk-go@v0.8.0'
go get -u 'github.com/sst/opencode-sdk-go@v0.5.0'
```
<!-- x-release-please-end -->
+2 -2
View File
@@ -143,10 +143,10 @@ Response Types:
- <a href="https://pkg.go.dev/github.com/sst/opencode-sdk-go">opencode</a>.<a href="https://pkg.go.dev/github.com/sst/opencode-sdk-go#ToolStatePending">ToolStatePending</a>
- <a href="https://pkg.go.dev/github.com/sst/opencode-sdk-go">opencode</a>.<a href="https://pkg.go.dev/github.com/sst/opencode-sdk-go#ToolStateRunning">ToolStateRunning</a>
- <a href="https://pkg.go.dev/github.com/sst/opencode-sdk-go">opencode</a>.<a href="https://pkg.go.dev/github.com/sst/opencode-sdk-go#UserMessage">UserMessage</a>
- <a href="https://pkg.go.dev/github.com/sst/opencode-sdk-go">opencode</a>.<a href="https://pkg.go.dev/github.com/sst/opencode-sdk-go#SessionChatResponse">SessionChatResponse</a>
- <a href="https://pkg.go.dev/github.com/sst/opencode-sdk-go">opencode</a>.<a href="https://pkg.go.dev/github.com/sst/opencode-sdk-go#SessionCommandResponse">SessionCommandResponse</a>
- <a href="https://pkg.go.dev/github.com/sst/opencode-sdk-go">opencode</a>.<a href="https://pkg.go.dev/github.com/sst/opencode-sdk-go#SessionMessageResponse">SessionMessageResponse</a>
- <a href="https://pkg.go.dev/github.com/sst/opencode-sdk-go">opencode</a>.<a href="https://pkg.go.dev/github.com/sst/opencode-sdk-go#SessionMessagesResponse">SessionMessagesResponse</a>
- <a href="https://pkg.go.dev/github.com/sst/opencode-sdk-go">opencode</a>.<a href="https://pkg.go.dev/github.com/sst/opencode-sdk-go#SessionPromptResponse">SessionPromptResponse</a>
Methods:
@@ -155,13 +155,13 @@ Methods:
- <code title="get /session">client.Session.<a href="https://pkg.go.dev/github.com/sst/opencode-sdk-go#SessionService.List">List</a>(ctx <a href="https://pkg.go.dev/context">context</a>.<a href="https://pkg.go.dev/context#Context">Context</a>, query <a href="https://pkg.go.dev/github.com/sst/opencode-sdk-go">opencode</a>.<a href="https://pkg.go.dev/github.com/sst/opencode-sdk-go#SessionListParams">SessionListParams</a>) ([]<a href="https://pkg.go.dev/github.com/sst/opencode-sdk-go">opencode</a>.<a href="https://pkg.go.dev/github.com/sst/opencode-sdk-go#Session">Session</a>, <a href="https://pkg.go.dev/builtin#error">error</a>)</code>
- <code title="delete /session/{id}">client.Session.<a href="https://pkg.go.dev/github.com/sst/opencode-sdk-go#SessionService.Delete">Delete</a>(ctx <a href="https://pkg.go.dev/context">context</a>.<a href="https://pkg.go.dev/context#Context">Context</a>, id <a href="https://pkg.go.dev/builtin#string">string</a>, body <a href="https://pkg.go.dev/github.com/sst/opencode-sdk-go">opencode</a>.<a href="https://pkg.go.dev/github.com/sst/opencode-sdk-go#SessionDeleteParams">SessionDeleteParams</a>) (<a href="https://pkg.go.dev/builtin#bool">bool</a>, <a href="https://pkg.go.dev/builtin#error">error</a>)</code>
- <code title="post /session/{id}/abort">client.Session.<a href="https://pkg.go.dev/github.com/sst/opencode-sdk-go#SessionService.Abort">Abort</a>(ctx <a href="https://pkg.go.dev/context">context</a>.<a href="https://pkg.go.dev/context#Context">Context</a>, id <a href="https://pkg.go.dev/builtin#string">string</a>, body <a href="https://pkg.go.dev/github.com/sst/opencode-sdk-go">opencode</a>.<a href="https://pkg.go.dev/github.com/sst/opencode-sdk-go#SessionAbortParams">SessionAbortParams</a>) (<a href="https://pkg.go.dev/builtin#bool">bool</a>, <a href="https://pkg.go.dev/builtin#error">error</a>)</code>
- <code title="post /session/{id}/message">client.Session.<a href="https://pkg.go.dev/github.com/sst/opencode-sdk-go#SessionService.Chat">Chat</a>(ctx <a href="https://pkg.go.dev/context">context</a>.<a href="https://pkg.go.dev/context#Context">Context</a>, id <a href="https://pkg.go.dev/builtin#string">string</a>, params <a href="https://pkg.go.dev/github.com/sst/opencode-sdk-go">opencode</a>.<a href="https://pkg.go.dev/github.com/sst/opencode-sdk-go#SessionChatParams">SessionChatParams</a>) (<a href="https://pkg.go.dev/github.com/sst/opencode-sdk-go">opencode</a>.<a href="https://pkg.go.dev/github.com/sst/opencode-sdk-go#SessionChatResponse">SessionChatResponse</a>, <a href="https://pkg.go.dev/builtin#error">error</a>)</code>
- <code title="get /session/{id}/children">client.Session.<a href="https://pkg.go.dev/github.com/sst/opencode-sdk-go#SessionService.Children">Children</a>(ctx <a href="https://pkg.go.dev/context">context</a>.<a href="https://pkg.go.dev/context#Context">Context</a>, id <a href="https://pkg.go.dev/builtin#string">string</a>, query <a href="https://pkg.go.dev/github.com/sst/opencode-sdk-go">opencode</a>.<a href="https://pkg.go.dev/github.com/sst/opencode-sdk-go#SessionChildrenParams">SessionChildrenParams</a>) ([]<a href="https://pkg.go.dev/github.com/sst/opencode-sdk-go">opencode</a>.<a href="https://pkg.go.dev/github.com/sst/opencode-sdk-go#Session">Session</a>, <a href="https://pkg.go.dev/builtin#error">error</a>)</code>
- <code title="post /session/{id}/command">client.Session.<a href="https://pkg.go.dev/github.com/sst/opencode-sdk-go#SessionService.Command">Command</a>(ctx <a href="https://pkg.go.dev/context">context</a>.<a href="https://pkg.go.dev/context#Context">Context</a>, id <a href="https://pkg.go.dev/builtin#string">string</a>, params <a href="https://pkg.go.dev/github.com/sst/opencode-sdk-go">opencode</a>.<a href="https://pkg.go.dev/github.com/sst/opencode-sdk-go#SessionCommandParams">SessionCommandParams</a>) (<a href="https://pkg.go.dev/github.com/sst/opencode-sdk-go">opencode</a>.<a href="https://pkg.go.dev/github.com/sst/opencode-sdk-go#SessionCommandResponse">SessionCommandResponse</a>, <a href="https://pkg.go.dev/builtin#error">error</a>)</code>
- <code title="get /session/{id}">client.Session.<a href="https://pkg.go.dev/github.com/sst/opencode-sdk-go#SessionService.Get">Get</a>(ctx <a href="https://pkg.go.dev/context">context</a>.<a href="https://pkg.go.dev/context#Context">Context</a>, id <a href="https://pkg.go.dev/builtin#string">string</a>, query <a href="https://pkg.go.dev/github.com/sst/opencode-sdk-go">opencode</a>.<a href="https://pkg.go.dev/github.com/sst/opencode-sdk-go#SessionGetParams">SessionGetParams</a>) (<a href="https://pkg.go.dev/github.com/sst/opencode-sdk-go">opencode</a>.<a href="https://pkg.go.dev/github.com/sst/opencode-sdk-go#Session">Session</a>, <a href="https://pkg.go.dev/builtin#error">error</a>)</code>
- <code title="post /session/{id}/init">client.Session.<a href="https://pkg.go.dev/github.com/sst/opencode-sdk-go#SessionService.Init">Init</a>(ctx <a href="https://pkg.go.dev/context">context</a>.<a href="https://pkg.go.dev/context#Context">Context</a>, id <a href="https://pkg.go.dev/builtin#string">string</a>, params <a href="https://pkg.go.dev/github.com/sst/opencode-sdk-go">opencode</a>.<a href="https://pkg.go.dev/github.com/sst/opencode-sdk-go#SessionInitParams">SessionInitParams</a>) (<a href="https://pkg.go.dev/builtin#bool">bool</a>, <a href="https://pkg.go.dev/builtin#error">error</a>)</code>
- <code title="get /session/{id}/message/{messageID}">client.Session.<a href="https://pkg.go.dev/github.com/sst/opencode-sdk-go#SessionService.Message">Message</a>(ctx <a href="https://pkg.go.dev/context">context</a>.<a href="https://pkg.go.dev/context#Context">Context</a>, id <a href="https://pkg.go.dev/builtin#string">string</a>, messageID <a href="https://pkg.go.dev/builtin#string">string</a>, query <a href="https://pkg.go.dev/github.com/sst/opencode-sdk-go">opencode</a>.<a href="https://pkg.go.dev/github.com/sst/opencode-sdk-go#SessionMessageParams">SessionMessageParams</a>) (<a href="https://pkg.go.dev/github.com/sst/opencode-sdk-go">opencode</a>.<a href="https://pkg.go.dev/github.com/sst/opencode-sdk-go#SessionMessageResponse">SessionMessageResponse</a>, <a href="https://pkg.go.dev/builtin#error">error</a>)</code>
- <code title="get /session/{id}/message">client.Session.<a href="https://pkg.go.dev/github.com/sst/opencode-sdk-go#SessionService.Messages">Messages</a>(ctx <a href="https://pkg.go.dev/context">context</a>.<a href="https://pkg.go.dev/context#Context">Context</a>, id <a href="https://pkg.go.dev/builtin#string">string</a>, query <a href="https://pkg.go.dev/github.com/sst/opencode-sdk-go">opencode</a>.<a href="https://pkg.go.dev/github.com/sst/opencode-sdk-go#SessionMessagesParams">SessionMessagesParams</a>) ([]<a href="https://pkg.go.dev/github.com/sst/opencode-sdk-go">opencode</a>.<a href="https://pkg.go.dev/github.com/sst/opencode-sdk-go#SessionMessagesResponse">SessionMessagesResponse</a>, <a href="https://pkg.go.dev/builtin#error">error</a>)</code>
- <code title="post /session/{id}/message">client.Session.<a href="https://pkg.go.dev/github.com/sst/opencode-sdk-go#SessionService.Prompt">Prompt</a>(ctx <a href="https://pkg.go.dev/context">context</a>.<a href="https://pkg.go.dev/context#Context">Context</a>, id <a href="https://pkg.go.dev/builtin#string">string</a>, params <a href="https://pkg.go.dev/github.com/sst/opencode-sdk-go">opencode</a>.<a href="https://pkg.go.dev/github.com/sst/opencode-sdk-go#SessionPromptParams">SessionPromptParams</a>) (<a href="https://pkg.go.dev/github.com/sst/opencode-sdk-go">opencode</a>.<a href="https://pkg.go.dev/github.com/sst/opencode-sdk-go#SessionPromptResponse">SessionPromptResponse</a>, <a href="https://pkg.go.dev/builtin#error">error</a>)</code>
- <code title="post /session/{id}/revert">client.Session.<a href="https://pkg.go.dev/github.com/sst/opencode-sdk-go#SessionService.Revert">Revert</a>(ctx <a href="https://pkg.go.dev/context">context</a>.<a href="https://pkg.go.dev/context#Context">Context</a>, id <a href="https://pkg.go.dev/builtin#string">string</a>, params <a href="https://pkg.go.dev/github.com/sst/opencode-sdk-go">opencode</a>.<a href="https://pkg.go.dev/github.com/sst/opencode-sdk-go#SessionRevertParams">SessionRevertParams</a>) (<a href="https://pkg.go.dev/github.com/sst/opencode-sdk-go">opencode</a>.<a href="https://pkg.go.dev/github.com/sst/opencode-sdk-go#Session">Session</a>, <a href="https://pkg.go.dev/builtin#error">error</a>)</code>
- <code title="post /session/{id}/share">client.Session.<a href="https://pkg.go.dev/github.com/sst/opencode-sdk-go#SessionService.Share">Share</a>(ctx <a href="https://pkg.go.dev/context">context</a>.<a href="https://pkg.go.dev/context#Context">Context</a>, id <a href="https://pkg.go.dev/builtin#string">string</a>, body <a href="https://pkg.go.dev/github.com/sst/opencode-sdk-go">opencode</a>.<a href="https://pkg.go.dev/github.com/sst/opencode-sdk-go#SessionShareParams">SessionShareParams</a>) (<a href="https://pkg.go.dev/github.com/sst/opencode-sdk-go">opencode</a>.<a href="https://pkg.go.dev/github.com/sst/opencode-sdk-go#Session">Session</a>, <a href="https://pkg.go.dev/builtin#error">error</a>)</code>
- <code title="post /session/{id}/shell">client.Session.<a href="https://pkg.go.dev/github.com/sst/opencode-sdk-go#SessionService.Shell">Shell</a>(ctx <a href="https://pkg.go.dev/context">context</a>.<a href="https://pkg.go.dev/context#Context">Context</a>, id <a href="https://pkg.go.dev/builtin#string">string</a>, params <a href="https://pkg.go.dev/github.com/sst/opencode-sdk-go">opencode</a>.<a href="https://pkg.go.dev/github.com/sst/opencode-sdk-go#SessionShellParams">SessionShellParams</a>) (<a href="https://pkg.go.dev/github.com/sst/opencode-sdk-go">opencode</a>.<a href="https://pkg.go.dev/github.com/sst/opencode-sdk-go#AssistantMessage">AssistantMessage</a>, <a href="https://pkg.go.dev/builtin#error">error</a>)</code>
+4 -36
View File
@@ -13,7 +13,6 @@ import (
"github.com/sst/opencode-sdk-go/internal/param"
"github.com/sst/opencode-sdk-go/internal/requestconfig"
"github.com/sst/opencode-sdk-go/option"
"github.com/sst/opencode-sdk-go/shared"
"github.com/tidwall/gjson"
)
@@ -1651,13 +1650,10 @@ func (r configProviderModelsLimitJSON) RawJSON() string {
}
type ConfigProviderOptions struct {
APIKey string `json:"apiKey"`
BaseURL string `json:"baseURL"`
// Timeout in milliseconds for requests to this provider. Default is 300000 (5
// minutes). Set to false to disable timeout.
Timeout ConfigProviderOptionsTimeoutUnion `json:"timeout"`
ExtraFields map[string]interface{} `json:"-,extras"`
JSON configProviderOptionsJSON `json:"-"`
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
@@ -1665,7 +1661,6 @@ type ConfigProviderOptions struct {
type configProviderOptionsJSON struct {
APIKey apijson.Field
BaseURL apijson.Field
Timeout apijson.Field
raw string
ExtraFields map[string]apijson.Field
}
@@ -1678,33 +1673,6 @@ func (r configProviderOptionsJSON) RawJSON() string {
return r.raw
}
// Timeout in milliseconds for requests to this provider. Default is 300000 (5
// minutes). Set to false to disable timeout.
//
// Union satisfied by [shared.UnionInt] or [shared.UnionBool].
type ConfigProviderOptionsTimeoutUnion interface {
ImplementsConfigProviderOptionsTimeoutUnion()
}
func init() {
apijson.RegisterUnion(
reflect.TypeOf((*ConfigProviderOptionsTimeoutUnion)(nil)).Elem(),
"",
apijson.UnionVariant{
TypeFilter: gjson.Number,
Type: reflect.TypeOf(shared.UnionInt(0)),
},
apijson.UnionVariant{
TypeFilter: gjson.True,
Type: reflect.TypeOf(shared.UnionBool(false)),
},
apijson.UnionVariant{
TypeFilter: gjson.False,
Type: reflect.TypeOf(shared.UnionBool(false)),
},
)
}
// Control sharing behavior:'manual' allows manual sharing via commands, 'auto'
// enables automatic sharing, 'disabled' disables all sharing
type ConfigShare string
+1 -1
View File
@@ -2,4 +2,4 @@
package internal
const PackageVersion = "0.8.0" // x-release-please-version
const PackageVersion = "0.5.0" // x-release-please-version
+3 -7
View File
@@ -42,19 +42,15 @@ func (r *PathService) Get(ctx context.Context, query PathGetParams, opts ...opti
}
type Path struct {
Config string `json:"config,required"`
Directory string `json:"directory,required"`
State string `json:"state,required"`
Worktree string `json:"worktree,required"`
JSON pathJSON `json:"-"`
Config string `json:"config,required"`
State string `json:"state,required"`
JSON pathJSON `json:"-"`
}
// pathJSON contains the JSON metadata for the struct [Path]
type pathJSON struct {
Config apijson.Field
Directory apijson.Field
State apijson.Field
Worktree apijson.Field
raw string
ExtraFields map[string]apijson.Field
}
+102 -110
View File
@@ -92,6 +92,18 @@ func (r *SessionService) Abort(ctx context.Context, id string, body SessionAbort
return
}
// Create and send a new message to a session
func (r *SessionService) Chat(ctx context.Context, id string, params SessionChatParams, opts ...option.RequestOption) (res *SessionChatResponse, err error) {
opts = append(r.Options[:], opts...)
if id == "" {
err = errors.New("missing required id parameter")
return
}
path := fmt.Sprintf("session/%s/message", id)
err = requestconfig.ExecuteNewRequest(ctx, http.MethodPost, path, params, &res, opts...)
return
}
// Get a session's children
func (r *SessionService) Children(ctx context.Context, id string, query SessionChildrenParams, opts ...option.RequestOption) (res *[]Session, err error) {
opts = append(r.Options[:], opts...)
@@ -168,18 +180,6 @@ func (r *SessionService) Messages(ctx context.Context, id string, query SessionM
return
}
// Create and send a new message to a session
func (r *SessionService) Prompt(ctx context.Context, id string, params SessionPromptParams, opts ...option.RequestOption) (res *SessionPromptResponse, err error) {
opts = append(r.Options[:], opts...)
if id == "" {
err = errors.New("missing required id parameter")
return
}
path := fmt.Sprintf("session/%s/message", id)
err = requestconfig.ExecuteNewRequest(ctx, http.MethodPost, path, params, &res, opts...)
return
}
// Revert a message
func (r *SessionService) Revert(ctx context.Context, id string, params SessionRevertParams, opts ...option.RequestOption) (res *Session, err error) {
opts = append(r.Options[:], opts...)
@@ -333,7 +333,7 @@ func (r AgentPartInputParam) MarshalJSON() (data []byte, err error) {
return apijson.MarshalRoot(r)
}
func (r AgentPartInputParam) implementsSessionPromptParamsPartUnion() {}
func (r AgentPartInputParam) implementsSessionChatParamsPartUnion() {}
type AgentPartInputType string
@@ -709,7 +709,7 @@ func (r FilePartInputParam) MarshalJSON() (data []byte, err error) {
return apijson.MarshalRoot(r)
}
func (r FilePartInputParam) implementsSessionPromptParamsPartUnion() {}
func (r FilePartInputParam) implementsSessionChatParamsPartUnion() {}
type FilePartInputType string
@@ -1820,7 +1820,7 @@ func (r TextPartInputParam) MarshalJSON() (data []byte, err error) {
return apijson.MarshalRoot(r)
}
func (r TextPartInputParam) implementsSessionPromptParamsPartUnion() {}
func (r TextPartInputParam) implementsSessionChatParamsPartUnion() {}
type TextPartInputType string
@@ -2296,6 +2296,29 @@ func (r userMessageTimeJSON) RawJSON() string {
return r.raw
}
type SessionChatResponse struct {
Info AssistantMessage `json:"info,required"`
Parts []Part `json:"parts,required"`
JSON sessionChatResponseJSON `json:"-"`
}
// sessionChatResponseJSON contains the JSON metadata for the struct
// [SessionChatResponse]
type sessionChatResponseJSON struct {
Info apijson.Field
Parts apijson.Field
raw string
ExtraFields map[string]apijson.Field
}
func (r *SessionChatResponse) UnmarshalJSON(data []byte) (err error) {
return apijson.UnmarshalRoot(data, r)
}
func (r sessionChatResponseJSON) RawJSON() string {
return r.raw
}
type SessionCommandResponse struct {
Info AssistantMessage `json:"info,required"`
Parts []Part `json:"parts,required"`
@@ -2365,29 +2388,6 @@ func (r sessionMessagesResponseJSON) RawJSON() string {
return r.raw
}
type SessionPromptResponse struct {
Info AssistantMessage `json:"info,required"`
Parts []Part `json:"parts,required"`
JSON sessionPromptResponseJSON `json:"-"`
}
// sessionPromptResponseJSON contains the JSON metadata for the struct
// [SessionPromptResponse]
type sessionPromptResponseJSON struct {
Info apijson.Field
Parts apijson.Field
raw string
ExtraFields map[string]apijson.Field
}
func (r *SessionPromptResponse) UnmarshalJSON(data []byte) (err error) {
return apijson.UnmarshalRoot(data, r)
}
func (r sessionPromptResponseJSON) RawJSON() string {
return r.raw
}
type SessionNewParams struct {
Directory param.Field[string] `query:"directory"`
ParentID param.Field[string] `json:"parentID"`
@@ -2459,6 +2459,70 @@ func (r SessionAbortParams) URLQuery() (v url.Values) {
})
}
type SessionChatParams struct {
ModelID param.Field[string] `json:"modelID,required"`
Parts param.Field[[]SessionChatParamsPartUnion] `json:"parts,required"`
ProviderID param.Field[string] `json:"providerID,required"`
Directory param.Field[string] `query:"directory"`
Agent param.Field[string] `json:"agent"`
MessageID param.Field[string] `json:"messageID"`
System param.Field[string] `json:"system"`
Tools param.Field[map[string]bool] `json:"tools"`
}
func (r SessionChatParams) MarshalJSON() (data []byte, err error) {
return apijson.MarshalRoot(r)
}
// URLQuery serializes [SessionChatParams]'s query parameters as `url.Values`.
func (r SessionChatParams) URLQuery() (v url.Values) {
return apiquery.MarshalWithSettings(r, apiquery.QuerySettings{
ArrayFormat: apiquery.ArrayQueryFormatComma,
NestedFormat: apiquery.NestedQueryFormatBrackets,
})
}
type SessionChatParamsPart struct {
Type param.Field[SessionChatParamsPartsType] `json:"type,required"`
ID param.Field[string] `json:"id"`
Filename param.Field[string] `json:"filename"`
Mime param.Field[string] `json:"mime"`
Name param.Field[string] `json:"name"`
Source param.Field[interface{}] `json:"source"`
Synthetic param.Field[bool] `json:"synthetic"`
Text param.Field[string] `json:"text"`
Time param.Field[interface{}] `json:"time"`
URL param.Field[string] `json:"url"`
}
func (r SessionChatParamsPart) MarshalJSON() (data []byte, err error) {
return apijson.MarshalRoot(r)
}
func (r SessionChatParamsPart) implementsSessionChatParamsPartUnion() {}
// Satisfied by [TextPartInputParam], [FilePartInputParam], [AgentPartInputParam],
// [SessionChatParamsPart].
type SessionChatParamsPartUnion interface {
implementsSessionChatParamsPartUnion()
}
type SessionChatParamsPartsType string
const (
SessionChatParamsPartsTypeText SessionChatParamsPartsType = "text"
SessionChatParamsPartsTypeFile SessionChatParamsPartsType = "file"
SessionChatParamsPartsTypeAgent SessionChatParamsPartsType = "agent"
)
func (r SessionChatParamsPartsType) IsKnown() bool {
switch r {
case SessionChatParamsPartsTypeText, SessionChatParamsPartsTypeFile, SessionChatParamsPartsTypeAgent:
return true
}
return false
}
type SessionChildrenParams struct {
Directory param.Field[string] `query:"directory"`
}
@@ -2547,78 +2611,6 @@ func (r SessionMessagesParams) URLQuery() (v url.Values) {
})
}
type SessionPromptParams struct {
Parts param.Field[[]SessionPromptParamsPartUnion] `json:"parts,required"`
Directory param.Field[string] `query:"directory"`
Agent param.Field[string] `json:"agent"`
MessageID param.Field[string] `json:"messageID"`
Model param.Field[SessionPromptParamsModel] `json:"model"`
System param.Field[string] `json:"system"`
Tools param.Field[map[string]bool] `json:"tools"`
}
func (r SessionPromptParams) MarshalJSON() (data []byte, err error) {
return apijson.MarshalRoot(r)
}
// URLQuery serializes [SessionPromptParams]'s query parameters as `url.Values`.
func (r SessionPromptParams) URLQuery() (v url.Values) {
return apiquery.MarshalWithSettings(r, apiquery.QuerySettings{
ArrayFormat: apiquery.ArrayQueryFormatComma,
NestedFormat: apiquery.NestedQueryFormatBrackets,
})
}
type SessionPromptParamsPart struct {
Type param.Field[SessionPromptParamsPartsType] `json:"type,required"`
ID param.Field[string] `json:"id"`
Filename param.Field[string] `json:"filename"`
Mime param.Field[string] `json:"mime"`
Name param.Field[string] `json:"name"`
Source param.Field[interface{}] `json:"source"`
Synthetic param.Field[bool] `json:"synthetic"`
Text param.Field[string] `json:"text"`
Time param.Field[interface{}] `json:"time"`
URL param.Field[string] `json:"url"`
}
func (r SessionPromptParamsPart) MarshalJSON() (data []byte, err error) {
return apijson.MarshalRoot(r)
}
func (r SessionPromptParamsPart) implementsSessionPromptParamsPartUnion() {}
// Satisfied by [TextPartInputParam], [FilePartInputParam], [AgentPartInputParam],
// [SessionPromptParamsPart].
type SessionPromptParamsPartUnion interface {
implementsSessionPromptParamsPartUnion()
}
type SessionPromptParamsPartsType string
const (
SessionPromptParamsPartsTypeText SessionPromptParamsPartsType = "text"
SessionPromptParamsPartsTypeFile SessionPromptParamsPartsType = "file"
SessionPromptParamsPartsTypeAgent SessionPromptParamsPartsType = "agent"
)
func (r SessionPromptParamsPartsType) IsKnown() bool {
switch r {
case SessionPromptParamsPartsTypeText, SessionPromptParamsPartsTypeFile, SessionPromptParamsPartsTypeAgent:
return true
}
return false
}
type SessionPromptParamsModel struct {
ModelID param.Field[string] `json:"modelID,required"`
ProviderID param.Field[string] `json:"providerID,required"`
}
func (r SessionPromptParamsModel) MarshalJSON() (data []byte, err error) {
return apijson.MarshalRoot(r)
}
type SessionRevertParams struct {
MessageID param.Field[string] `json:"messageID,required"`
Directory param.Field[string] `query:"directory"`
+46 -48
View File
@@ -148,6 +148,52 @@ func TestSessionAbortWithOptionalParams(t *testing.T) {
}
}
func TestSessionChatWithOptionalParams(t *testing.T) {
t.Skip("Prism tests are disabled")
baseURL := "http://localhost:4010"
if envURL, ok := os.LookupEnv("TEST_API_BASE_URL"); ok {
baseURL = envURL
}
if !testutil.CheckTestServer(t, baseURL) {
return
}
client := opencode.NewClient(
option.WithBaseURL(baseURL),
)
_, err := client.Session.Chat(
context.TODO(),
"id",
opencode.SessionChatParams{
ModelID: opencode.F("modelID"),
Parts: opencode.F([]opencode.SessionChatParamsPartUnion{opencode.TextPartInputParam{
Text: opencode.F("text"),
Type: opencode.F(opencode.TextPartInputTypeText),
ID: opencode.F("id"),
Synthetic: opencode.F(true),
Time: opencode.F(opencode.TextPartInputTimeParam{
Start: opencode.F(0.000000),
End: opencode.F(0.000000),
}),
}}),
ProviderID: opencode.F("providerID"),
Directory: opencode.F("directory"),
Agent: opencode.F("agent"),
MessageID: opencode.F("msg"),
System: opencode.F("system"),
Tools: opencode.F(map[string]bool{
"foo": true,
}),
},
)
if err != nil {
var apierr *opencode.Error
if errors.As(err, &apierr) {
t.Log(string(apierr.DumpRequest(true)))
}
t.Fatalf("err should be nil: %s", err.Error())
}
}
func TestSessionChildrenWithOptionalParams(t *testing.T) {
t.Skip("Prism tests are disabled")
baseURL := "http://localhost:4010"
@@ -325,54 +371,6 @@ func TestSessionMessagesWithOptionalParams(t *testing.T) {
}
}
func TestSessionPromptWithOptionalParams(t *testing.T) {
t.Skip("Prism tests are disabled")
baseURL := "http://localhost:4010"
if envURL, ok := os.LookupEnv("TEST_API_BASE_URL"); ok {
baseURL = envURL
}
if !testutil.CheckTestServer(t, baseURL) {
return
}
client := opencode.NewClient(
option.WithBaseURL(baseURL),
)
_, err := client.Session.Prompt(
context.TODO(),
"id",
opencode.SessionPromptParams{
Parts: opencode.F([]opencode.SessionPromptParamsPartUnion{opencode.TextPartInputParam{
Text: opencode.F("text"),
Type: opencode.F(opencode.TextPartInputTypeText),
ID: opencode.F("id"),
Synthetic: opencode.F(true),
Time: opencode.F(opencode.TextPartInputTimeParam{
Start: opencode.F(0.000000),
End: opencode.F(0.000000),
}),
}}),
Directory: opencode.F("directory"),
Agent: opencode.F("agent"),
MessageID: opencode.F("msg"),
Model: opencode.F(opencode.SessionPromptParamsModel{
ModelID: opencode.F("modelID"),
ProviderID: opencode.F("providerID"),
}),
System: opencode.F("system"),
Tools: opencode.F(map[string]bool{
"foo": true,
}),
},
)
if err != nil {
var apierr *opencode.Error
if errors.As(err, &apierr) {
t.Log(string(apierr.DumpRequest(true)))
}
t.Fatalf("err should be nil: %s", err.Error())
}
}
func TestSessionRevertWithOptionalParams(t *testing.T) {
t.Skip("Prism tests are disabled")
baseURL := "http://localhost:4010"
-11
View File
@@ -1,11 +0,0 @@
// File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
package shared
type UnionBool bool
func (UnionBool) ImplementsConfigProviderOptionsTimeoutUnion() {}
type UnionInt int64
func (UnionInt) ImplementsConfigProviderOptionsTimeoutUnion() {}
-55
View File
@@ -1,55 +0,0 @@
import { createOpencodeClient, createOpencodeServer } from "@opencode-ai/sdk"
const server = await createOpencodeServer()
const client = createOpencodeClient({ baseUrl: server.url })
const input = await Array.fromAsync(new Bun.Glob("packages/core/*.ts").scan())
const tasks: Promise<void>[] = []
for await (const file of input) {
console.log("processing", file)
const session = await client.session.create()
tasks.push(
client.session.prompt({
path: { id: session.data.id },
body: {
parts: [
{
type: "file",
mime: "text/plain",
url: `file://${file}`,
},
{
type: "text",
text: `Write tests for every public function in this file.`,
},
],
},
}),
)
console.log("done", file)
}
await Promise.all(
input.map(async (file) => {
const session = await client.session.create()
console.log("processing", file)
await client.session.prompt({
path: { id: session.data.id },
body: {
parts: [
{
type: "file",
mime: "text/plain",
url: `file://${file}`,
},
{
type: "text",
text: `Write tests for every public function in this file.`,
},
],
},
})
console.log("done", file)
}),
)
+1 -1
View File
@@ -1,7 +1,7 @@
{
"$schema": "https://json.schemastore.org/package.json",
"name": "@opencode-ai/sdk",
"version": "0.6.0",
"version": "0.5.29",
"type": "module",
"scripts": {
"typecheck": "tsc --noEmit"
+4 -16
View File
@@ -4,8 +4,6 @@ import type { Options as ClientOptions, TDataShape, Client } from "./client/inde
import type {
ProjectListData,
ProjectListResponses,
ProjectCurrentData,
ProjectCurrentResponses,
EventSubscribeData,
EventSubscribeResponses,
ConfigGetData,
@@ -37,8 +35,8 @@ import type {
SessionSummarizeResponses,
SessionMessagesData,
SessionMessagesResponses,
SessionPromptData,
SessionPromptResponses,
SessionChatData,
SessionChatResponses,
SessionMessageData,
SessionMessageResponses,
SessionCommandData,
@@ -132,16 +130,6 @@ class Project extends _HeyApiClient {
...options,
})
}
/**
* Get the current project
*/
public current<ThrowOnError extends boolean = false>(options?: Options<ProjectCurrentData, ThrowOnError>) {
return (options?.client ?? this._client).get<ProjectCurrentResponses, unknown, ThrowOnError>({
url: "/project/current",
...options,
})
}
}
class Event extends _HeyApiClient {
@@ -330,8 +318,8 @@ class Session extends _HeyApiClient {
/**
* Create and send a new message to a session
*/
public prompt<ThrowOnError extends boolean = false>(options: Options<SessionPromptData, ThrowOnError>) {
return (options.client ?? this._client).post<SessionPromptResponses, unknown, ThrowOnError>({
public chat<ThrowOnError extends boolean = false>(options: Options<SessionChatData, ThrowOnError>) {
return (options.client ?? this._client).post<SessionChatResponses, unknown, ThrowOnError>({
url: "/session/{id}/message",
...options,
headers: {
+6 -32
View File
@@ -645,11 +645,7 @@ export type Config = {
options?: {
apiKey?: string
baseURL?: string
/**
* Timeout in milliseconds for requests to this provider. Default is 300000 (5 minutes). Set to false to disable timeout.
*/
timeout?: number | false
[key: string]: unknown | string | (number | false) | undefined
[key: string]: unknown | string | undefined
}
}
}
@@ -1056,8 +1052,6 @@ export type LayoutConfig = "auto" | "stretch"
export type Path = {
state: string
config: string
worktree: string
directory: string
}
export type _Error = {
@@ -1202,24 +1196,6 @@ export type ProjectListResponses = {
export type ProjectListResponse = ProjectListResponses[keyof ProjectListResponses]
export type ProjectCurrentData = {
body?: never
path?: never
query?: {
directory?: string
}
url: "/project/current"
}
export type ProjectCurrentResponses = {
/**
* Current project
*/
200: Project
}
export type ProjectCurrentResponse = ProjectCurrentResponses[keyof ProjectCurrentResponses]
export type EventSubscribeData = {
body?: never
path?: never
@@ -1543,13 +1519,11 @@ export type SessionMessagesResponses = {
export type SessionMessagesResponse = SessionMessagesResponses[keyof SessionMessagesResponses]
export type SessionPromptData = {
export type SessionChatData = {
body?: {
messageID?: string
model?: {
providerID: string
modelID: string
}
providerID: string
modelID: string
agent?: string
system?: string
tools?: {
@@ -1579,7 +1553,7 @@ export type SessionPromptData = {
url: "/session/{id}/message"
}
export type SessionPromptResponses = {
export type SessionChatResponses = {
/**
* Created message
*/
@@ -1589,7 +1563,7 @@ export type SessionPromptResponses = {
}
}
export type SessionPromptResponse = SessionPromptResponses[keyof SessionPromptResponses]
export type SessionChatResponse = SessionChatResponses[keyof SessionChatResponses]
export type SessionMessageData = {
body?: never
+1 -1
View File
@@ -147,7 +147,7 @@ resources:
summarize: post /session/{id}/summarize
message: get /session/{id}/message/{messageID}
messages: get /session/{id}/message
prompt: post /session/{id}/message
chat: post /session/{id}/message
command: post /session/{id}/command
shell: post /session/{id}/shell
update: patch /session/{id}
+6 -8
View File
@@ -786,14 +786,12 @@ func (a *App) SendPrompt(ctx context.Context, prompt Prompt) (*App, tea.Cmd) {
a.Messages = append(a.Messages, message)
cmds = append(cmds, func() tea.Msg {
_, err := a.Client.Session.Prompt(ctx, a.Session.ID, opencode.SessionPromptParams{
Model: opencode.F(opencode.SessionPromptParamsModel{
ProviderID: opencode.F(a.Provider.ID),
ModelID: opencode.F(a.Model.ID),
}),
Agent: opencode.F(a.Agent().Name),
MessageID: opencode.F(messageID),
Parts: opencode.F(message.ToSessionChatParams()),
_, err := a.Client.Session.Chat(ctx, a.Session.ID, opencode.SessionChatParams{
ProviderID: opencode.F(a.Provider.ID),
ModelID: opencode.F(a.Model.ID),
Agent: opencode.F(a.Agent().Name),
MessageID: opencode.F(messageID),
Parts: opencode.F(message.ToSessionChatParams()),
})
if err != nil {
errormsg := fmt.Sprintf("failed to send message: %v", err)
+2 -5
View File
@@ -43,9 +43,6 @@ func (p Prompt) ToMessage(
}
for _, att := range textAttachments {
if source, ok := att.GetTextSource(); ok {
if att.StartIndex > att.EndIndex || att.EndIndex > len(text) {
continue
}
text = text[:att.StartIndex] + source.Value + text[att.EndIndex:]
}
}
@@ -207,8 +204,8 @@ func (m Message) ToPrompt() (*Prompt, error) {
return nil, errors.New("unknown message type")
}
func (m Message) ToSessionChatParams() []opencode.SessionPromptParamsPartUnion {
parts := []opencode.SessionPromptParamsPartUnion{}
func (m Message) ToSessionChatParams() []opencode.SessionChatParamsPartUnion {
parts := []opencode.SessionChatParamsPartUnion{}
for _, part := range m.Parts {
switch p := part.(type) {
case opencode.TextPart:
+1 -1
View File
@@ -1,7 +1,7 @@
{
"name": "@opencode/web",
"type": "module",
"version": "0.6.0",
"version": "0.5.29",
"scripts": {
"dev": "astro dev",
"dev:remote": "sst shell --stage=dev --target=Web astro dev",
@@ -9,7 +9,7 @@ you to use opencode at your organization.
To get started, we recommend:
1. Do a trial internally with your team.
2. [**Contact us**](mailto:contact@anoma.ly) to discuss pricing and implementation options.
2. [**Contact us**](mailto:hello@anoma.ly) to discuss pricing and implementation options.
---
@@ -55,7 +55,7 @@ We recommend you disable this for your trial.
## Deployment
Once you have completed your trial and you are ready to self-host opencode at
your organization, you can [**contact us**](mailto:contact@anoma.ly) to discuss
your organization, you can [**contact us**](mailto:hello@anoma.ly) to discuss
pricing and implementation options.
---
@@ -26,7 +26,7 @@ Plugins are loaded from:
### Basic structure
```js title=".opencode/plugin/example.js"
export const MyPlugin = async ({ project, client, $, directory, worktree }) => {
export const MyPlugin = async ({ app, client, $ }) => {
console.log("Plugin initialized!")
return {
@@ -37,9 +37,7 @@ export const MyPlugin = async ({ project, client, $, directory, worktree }) => {
The plugin function receives:
- `project`: The current project information.
- `directory`: The current working directory.
- `worktree`: The git worktree path.
- `app`: The opencode application instance.
- `client`: An opencode SDK client for interacting with the AI.
- `$`: Bun's [shell API](https://bun.com/docs/runtime/shell) for executing commands.
@@ -52,7 +50,7 @@ For TypeScript plugins, you can import types from the plugin package:
```ts title="my-plugin.ts" {1}
import type { Plugin } from "@opencode-ai/plugin"
export const MyPlugin: Plugin = async ({ project, client, $, directory, worktree }) => {
export const MyPlugin: Plugin = async ({ app, client, $ }) => {
return {
// Type-safe hook implementations
}
@@ -72,7 +70,7 @@ Here are some examples of plugins you can use to extend opencode.
Send notifications when certain events occur:
```js title=".opencode/plugin/notification.js"
export const NotificationPlugin = async ({ project, client, $, directory, worktree }) => {
export const NotificationPlugin = async ({ client, $ }) => {
return {
event: async ({ event }) => {
// Send notification on session completion
@@ -93,13 +91,13 @@ We are using `osascript` to run AppleScript on macOS. Here we are using it to se
Prevent opencode from reading `.env` files:
```javascript title=".opencode/plugin/env-protection.js"
export const EnvProtection = async ({ project, client, $, directory, worktree }) => {
export const EnvProtection = async ({ client, $ }) => {
return {
"tool.execute.before": async (input, output) => {
if (input.tool === "read" && output.args.filePath.includes(".env")) {
throw new Error("Do not read .env files")
}
},
}
}
}
```
+17 -66
View File
@@ -10,8 +10,6 @@ The opencode [JS/TS SDK](https://www.npmjs.com/package/@opencode-ai/sdk) provide
[Learn more](/docs/server) about how the opencode server works.
> **Note**: Many API endpoints now require a `directory` query parameter to specify the working directory context.
---
## Install
@@ -67,12 +65,12 @@ server.close()
#### Options
| Option | Type | Description | Default |
| ---------- | ------------- | ------------------------------ | ----------- |
| `hostname` | `string` | Server hostname | `127.0.0.1` |
| `port` | `number` | Server port | `4096` |
| `signal` | `AbortSignal` | Abort signal for cancellation | `undefined` |
| `timeout` | `number` | Timeout in ms for server start | `5000` |
| Option | Type | Description | Default |
| ---------- | -------------- | ------------------------------ | ------------- |
| `hostname` | `string` | Server hostname | `127.0.0.1` |
| `port` | `number` | Server port | `4096` |
| `signal` | `AbortSignal` | Abort signal for cancellation | `undefined` |
| `timeout` | `number` | Timeout in ms for server start | `5000` |
---
@@ -82,7 +80,7 @@ The SDK includes TypeScript definitions for all API types. Import them directly:
```typescript
import type { Session, Message, Part } from "@opencode-ai/sdk"
```
````
All types are generated from the server's OpenAPI specification and available in the <a href={typesUrl}>types file</a>.
@@ -110,63 +108,18 @@ The SDK exposes all server APIs through a type-safe client interface.
### App
| Method | Description | Response |
| -------------- | ------------------------- | ------------------------------------------- |
| `app.log()` | Write a log entry | `boolean` |
| `app.agents()` | List all available agents | <a href={typesUrl}><code>Agent[]</code></a> |
| Method | Description | Response |
| ------------ | ------------------ | --------------------------------------- |
| `app.get()` | Get app info | <a href={typesUrl}><code>App</code></a> |
| `app.init()` | Initialize the app | `boolean` |
---
#### Examples
```javascript
// Log an entry
await client.app.log({
service: "my-app",
level: "info",
message: "Operation completed",
})
// List available agents
const agents = await client.app.agents()
```
---
### Project
| Method | Description | Response |
| ------------------- | ------------------- | --------------------------------------------- |
| `project.list()` | List all projects | <a href={typesUrl}><code>Project[]</code></a> |
| `project.current()` | Get current project | <a href={typesUrl}><code>Project</code></a> |
---
#### Examples
```javascript
// List all projects
const projects = await client.project.list()
// Get current project
const currentProject = await client.project.current()
```
---
### Path
| Method | Description | Response |
| ------------ | ---------------- | ---------------------------------------- |
| `path.get()` | Get current path | <a href={typesUrl}><code>Path</code></a> |
---
#### Examples
```javascript
// Get current path information
const pathInfo = await client.path.get()
const app = await client.app.get()
await client.app.init()
```
---
@@ -206,7 +159,7 @@ const { providers, default: defaults } = await client.config.providers()
| `session.summarize({ id, providerID, modelID })` | Summarize session | Returns `boolean` |
| `session.messages({ id })` | List messages in a session | Returns `{ info: `<a href={typesUrl}><code>Message</code></a>`, parts: `<a href={typesUrl}><code>Part[]</code></a>`}[]` |
| `session.message({ id, messageID })` | Get message details | Returns `{ info: `<a href={typesUrl}><code>Message</code></a>`, parts: `<a href={typesUrl}><code>Part[]</code></a>`}` |
| `session.prompt({ id, ...promptInput })` | Send prompt message | Returns <a href={typesUrl}><code>Message</code></a> |
| `session.chat({ id, ...chatInput })` | Send chat message | Returns <a href={typesUrl}><code>Message</code></a> |
| `session.shell({ id, agent, command })` | Run a shell command | Returns <a href={typesUrl}><code>Message</code></a> |
| `session.revert({ id, messageID, partID? })` | Revert a message | Returns <a href={typesUrl}><code>Session</code></a> |
| `session.unrevert({ id })` | Restore reverted messages | Returns <a href={typesUrl}><code>Session</code></a> |
@@ -222,12 +175,10 @@ const session = await client.session.create({ title: "My session" })
const sessions = await client.session.list()
// Send messages
const message = await client.session.prompt({
const message = await client.session.chat({
id: session.id,
model: {
providerID: "anthropic",
modelID: "claude-3-5-sonnet-20241022",
},
providerID: "anthropic",
modelID: "claude-3-5-sonnet-20241022",
parts: [{ type: "text", text: "Hello!" }],
})
```
+1 -1
View File
@@ -2,7 +2,7 @@
"name": "opencode",
"displayName": "opencode",
"description": "opencode for VS Code",
"version": "0.6.0",
"version": "0.5.29",
"publisher": "sst-dev",
"repository": {
"type": "git",