summaryrefslogtreecommitdiffhomepage
path: root/packages
diff options
context:
space:
mode:
Diffstat (limited to 'packages')
-rw-r--r--packages/opencode/src/bus/index.ts8
-rw-r--r--packages/opencode/src/plugin/index.ts3
-rw-r--r--packages/opencode/src/server/server.ts2309
-rw-r--r--packages/opencode/test/tool/register.test.ts16
-rw-r--r--packages/sdk/go/.release-please-manifest.json2
-rw-r--r--packages/sdk/go/.stats.yml4
-rw-r--r--packages/sdk/go/CHANGELOG.md8
-rw-r--r--packages/sdk/go/README.md2
-rw-r--r--packages/sdk/go/config.go26
-rw-r--r--packages/sdk/go/event.go164
-rw-r--r--packages/sdk/go/internal/version.go2
-rw-r--r--packages/sdk/js/src/gen/client/client.gen.ts98
-rw-r--r--packages/sdk/js/src/gen/client/types.gen.ts12
-rw-r--r--packages/sdk/js/src/gen/client/utils.gen.ts12
-rw-r--r--packages/sdk/js/src/gen/core/serverSentEvents.gen.ts29
-rw-r--r--packages/sdk/js/src/gen/core/types.gen.ts19
-rw-r--r--packages/sdk/js/src/gen/core/utils.gen.ts30
-rw-r--r--packages/sdk/js/src/gen/sdk.gen.ts30
-rw-r--r--packages/sdk/js/src/gen/types.gen.ts921
19 files changed, 1996 insertions, 1699 deletions
diff --git a/packages/opencode/src/bus/index.ts b/packages/opencode/src/bus/index.ts
index cfd3958d2..7fbefba44 100644
--- a/packages/opencode/src/bus/index.ts
+++ b/packages/opencode/src/bus/index.ts
@@ -33,16 +33,16 @@ export namespace Bus {
"type",
registry
.entries()
- .map(([type, def]) =>
- z
+ .map(([type, def]) => {
+ return z
.object({
type: z.literal(type),
properties: def.properties,
})
.meta({
ref: "Event" + "." + def.type,
- }),
- )
+ })
+ })
.toArray() as any,
)
}
diff --git a/packages/opencode/src/plugin/index.ts b/packages/opencode/src/plugin/index.ts
index 71be1cd40..ab36087b1 100644
--- a/packages/opencode/src/plugin/index.ts
+++ b/packages/opencode/src/plugin/index.ts
@@ -15,7 +15,8 @@ export namespace Plugin {
const state = Instance.state(async () => {
const client = createOpencodeClient({
baseUrl: "http://localhost:4096",
- fetch: async (...args) => Server.App.fetch(...args),
+ // @ts-expect-error
+ fetch: async (...args) => Server.App().fetch(...args),
})
const config = await Config.get()
const hooks = []
diff --git a/packages/opencode/src/server/server.ts b/packages/opencode/src/server/server.ts
index fd44b0fde..3a5d794c5 100644
--- a/packages/opencode/src/server/server.ts
+++ b/packages/opencode/src/server/server.ts
@@ -28,6 +28,7 @@ import { zodToJsonSchema } from "zod-to-json-schema"
import { SessionPrompt } from "../session/prompt"
import { SessionCompaction } from "../session/compaction"
import { SessionRevert } from "../session/revert"
+import { lazy } from "../util/lazy"
const ERRORS = {
400: {
@@ -79,1343 +80,1345 @@ 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(), {
+ export const App = lazy(() =>
+ app
+ .onError((err, c) => {
+ log.error("failed", {
+ error: err,
+ })
+ if (err instanceof NamedError) {
+ return c.json(err.toObject(), {
+ status: 400,
+ })
+ }
+ return c.json(new NamedError.Unknown({ message: err.toString() }).toObject(), {
status: 400,
})
- }
- return c.json(new NamedError.Unknown({ message: err.toString() }).toObject(), {
- status: 400,
})
- })
- .use(async (c, next) => {
- const skipLogging = c.req.path === "/log"
- if (!skipLogging) {
- log.info("request", {
- method: c.req.method,
- path: c.req.path,
- })
- }
- const start = Date.now()
- await next()
- if (!skipLogging) {
- log.info("response", {
- duration: Date.now() - start,
+ .use(async (c, next) => {
+ const skipLogging = c.req.path === "/log"
+ if (!skipLogging) {
+ log.info("request", {
+ method: c.req.method,
+ path: c.req.path,
+ })
+ }
+ const start = Date.now()
+ await next()
+ if (!skipLogging) {
+ log.info("response", {
+ duration: Date.now() - start,
+ })
+ }
+ })
+ .use(async (c, next) => {
+ const directory = c.req.query("directory") ?? process.cwd()
+ return Instance.provide(directory, async () => {
+ return next()
})
- }
- })
- .use(async (c, next) => {
- const directory = c.req.query("directory") ?? process.cwd()
- return Instance.provide(directory, async () => {
- return next()
})
- })
- .use(cors())
- .get(
- "/doc",
- openAPIRouteHandler(app, {
- documentation: {
- info: {
- title: "opencode",
- version: "0.0.3",
- description: "opencode api",
- },
- openapi: "3.1.1",
- },
- }),
- )
- .use(validator("query", z.object({ directory: z.string().optional() })))
- .route("/project", ProjectRoute)
- .get(
- "/event",
- describeRoute({
- description: "Get events",
- operationId: "event.subscribe",
- responses: {
- 200: {
- description: "Event stream",
- content: {
- "text/event-stream": {
- schema: resolver(
- Bus.payloads().meta({
- ref: "Event",
- }),
- ),
- },
+ .use(cors())
+ .get(
+ "/doc",
+ openAPIRouteHandler(app, {
+ documentation: {
+ info: {
+ title: "opencode",
+ version: "0.0.3",
+ description: "opencode api",
},
+ openapi: "3.1.1",
},
- },
- }),
- async (c) => {
- log.info("event connected")
- return streamSSE(c, async (stream) => {
- stream.writeSSE({
- data: JSON.stringify({
- type: "server.connected",
- properties: {},
- }),
- })
- const unsub = Bus.subscribeAll(async (event) => {
- await stream.writeSSE({
- data: JSON.stringify(event),
- })
- })
- await new Promise<void>((resolve) => {
- stream.onAbort(() => {
- unsub()
- resolve()
- log.info("event disconnected")
- })
- })
- })
- },
- )
- .get(
- "/config",
- describeRoute({
- description: "Get config info",
- operationId: "config.get",
- responses: {
- 200: {
- description: "Get config info",
- content: {
- "application/json": {
- schema: resolver(Config.Info),
+ }),
+ )
+ .use(validator("query", z.object({ directory: z.string().optional() })))
+ .route("/project", ProjectRoute)
+ .get(
+ "/config",
+ describeRoute({
+ description: "Get config info",
+ operationId: "config.get",
+ responses: {
+ 200: {
+ description: "Get config info",
+ content: {
+ "application/json": {
+ schema: resolver(Config.Info),
+ },
},
},
},
+ }),
+ async (c) => {
+ return c.json(await Config.get())
},
- }),
- async (c) => {
- return c.json(await Config.get())
- },
- )
- .post(
- "/experimental/tool/register",
- describeRoute({
- description: "Register a new HTTP callback tool",
- operationId: "tool.register",
- responses: {
- 200: {
- description: "Tool registered successfully",
- content: {
- "application/json": {
- schema: resolver(z.boolean()),
+ )
+ .post(
+ "/experimental/tool/register",
+ describeRoute({
+ description: "Register a new HTTP callback tool",
+ operationId: "tool.register",
+ responses: {
+ 200: {
+ description: "Tool registered successfully",
+ content: {
+ "application/json": {
+ schema: resolver(z.boolean()),
+ },
},
},
+ ...ERRORS,
},
- ...ERRORS,
+ }),
+ validator("json", HttpToolRegistration),
+ async (c) => {
+ ToolRegistry.registerHTTP(c.req.valid("json"))
+ return c.json(true)
},
- }),
- validator("json", HttpToolRegistration),
- async (c) => {
- ToolRegistry.registerHTTP(c.req.valid("json"))
- return c.json(true)
- },
- )
- .get(
- "/experimental/tool/ids",
- describeRoute({
- description: "List all tool IDs (including built-in and dynamically registered)",
- operationId: "tool.ids",
- responses: {
- 200: {
- description: "Tool IDs",
- content: {
- "application/json": {
- schema: resolver(z.array(z.string()).meta({ ref: "ToolIDs" })),
+ )
+ .get(
+ "/experimental/tool/ids",
+ describeRoute({
+ description: "List all tool IDs (including built-in and dynamically registered)",
+ operationId: "tool.ids",
+ responses: {
+ 200: {
+ description: "Tool IDs",
+ content: {
+ "application/json": {
+ schema: resolver(z.array(z.string()).meta({ ref: "ToolIDs" })),
+ },
},
},
+ ...ERRORS,
},
- ...ERRORS,
+ }),
+ async (c) => {
+ return c.json(ToolRegistry.ids())
},
- }),
- async (c) => {
- return c.json(ToolRegistry.ids())
- },
- )
- .get(
- "/experimental/tool",
- describeRoute({
- description: "List tools with JSON schema parameters for a provider/model",
- operationId: "tool.list",
- responses: {
- 200: {
- description: "Tools",
- content: {
- "application/json": {
- schema: resolver(
- z
- .array(
- z
- .object({
- id: z.string(),
- description: z.string(),
- parameters: z.any(),
- })
- .meta({ ref: "ToolListItem" }),
- )
- .meta({ ref: "ToolList" }),
- ),
+ )
+ .get(
+ "/experimental/tool",
+ describeRoute({
+ description: "List tools with JSON schema parameters for a provider/model",
+ operationId: "tool.list",
+ responses: {
+ 200: {
+ description: "Tools",
+ content: {
+ "application/json": {
+ schema: resolver(
+ z
+ .array(
+ z
+ .object({
+ id: z.string(),
+ description: z.string(),
+ parameters: z.any(),
+ })
+ .meta({ ref: "ToolListItem" }),
+ )
+ .meta({ ref: "ToolList" }),
+ ),
+ },
},
},
+ ...ERRORS,
},
- ...ERRORS,
- },
- }),
- validator(
- "query",
- z.object({
- provider: z.string(),
- model: z.string(),
}),
- ),
- async (c) => {
- const { provider, model } = c.req.valid("query")
- const tools = await ToolRegistry.tools(provider, model)
- return c.json(
- tools.map((t) => ({
- id: t.id,
- description: t.description,
- // Handle both Zod schemas and plain JSON schemas
- parameters: (t.parameters as any)?._def ? zodToJsonSchema(t.parameters as any) : t.parameters,
- })),
- )
- },
- )
- .get(
- "/path",
- describeRoute({
- description: "Get the current path",
- operationId: "path.get",
- responses: {
- 200: {
- description: "Path",
- content: {
- "application/json": {
- schema: resolver(
- z
- .object({
- state: z.string(),
- config: z.string(),
- worktree: z.string(),
- directory: z.string(),
- })
- .meta({
- ref: "Path",
- }),
- ),
+ validator(
+ "query",
+ z.object({
+ provider: z.string(),
+ model: z.string(),
+ }),
+ ),
+ async (c) => {
+ const { provider, model } = c.req.valid("query")
+ const tools = await ToolRegistry.tools(provider, model)
+ return c.json(
+ tools.map((t) => ({
+ id: t.id,
+ description: t.description,
+ // Handle both Zod schemas and plain JSON schemas
+ parameters: (t.parameters as any)?._def ? zodToJsonSchema(t.parameters as any) : t.parameters,
+ })),
+ )
+ },
+ )
+ .get(
+ "/path",
+ describeRoute({
+ description: "Get the current path",
+ operationId: "path.get",
+ responses: {
+ 200: {
+ description: "Path",
+ content: {
+ "application/json": {
+ schema: resolver(
+ z
+ .object({
+ state: z.string(),
+ config: z.string(),
+ worktree: z.string(),
+ directory: z.string(),
+ })
+ .meta({
+ ref: "Path",
+ }),
+ ),
+ },
},
},
},
+ }),
+ async (c) => {
+ return c.json({
+ state: Global.Path.state,
+ config: Global.Path.config,
+ worktree: Instance.worktree,
+ directory: Instance.directory,
+ })
},
- }),
- async (c) => {
- return c.json({
- state: Global.Path.state,
- config: Global.Path.config,
- worktree: Instance.worktree,
- directory: Instance.directory,
- })
- },
- )
- .get(
- "/session",
- describeRoute({
- description: "List all sessions",
- operationId: "session.list",
- responses: {
- 200: {
- description: "List of sessions",
- content: {
- "application/json": {
- schema: resolver(Session.Info.array()),
+ )
+ .get(
+ "/session",
+ describeRoute({
+ description: "List all sessions",
+ operationId: "session.list",
+ responses: {
+ 200: {
+ description: "List of sessions",
+ content: {
+ "application/json": {
+ schema: resolver(Session.Info.array()),
+ },
},
},
},
+ }),
+ async (c) => {
+ const sessions = await Array.fromAsync(Session.list())
+ sessions.sort((a, b) => b.time.updated - a.time.updated)
+ return c.json(sessions)
},
- }),
- async (c) => {
- const sessions = await Array.fromAsync(Session.list())
- sessions.sort((a, b) => b.time.updated - a.time.updated)
- return c.json(sessions)
- },
- )
- .get(
- "/session/:id",
- describeRoute({
- description: "Get session",
- operationId: "session.get",
- responses: {
- 200: {
- description: "Get session",
- content: {
- "application/json": {
- schema: resolver(Session.Info),
+ )
+ .get(
+ "/session/:id",
+ describeRoute({
+ description: "Get session",
+ operationId: "session.get",
+ responses: {
+ 200: {
+ description: "Get session",
+ content: {
+ "application/json": {
+ schema: resolver(Session.Info),
+ },
},
},
},
- },
- }),
- validator(
- "param",
- z.object({
- id: z.string(),
}),
- ),
- async (c) => {
- const sessionID = c.req.valid("param").id
- const session = await Session.get(sessionID)
- return c.json(session)
- },
- )
- .get(
- "/session/:id/children",
- describeRoute({
- description: "Get a session's children",
- operationId: "session.children",
- responses: {
- 200: {
- description: "List of children",
- content: {
- "application/json": {
- schema: resolver(Session.Info.array()),
+ validator(
+ "param",
+ z.object({
+ id: z.string(),
+ }),
+ ),
+ async (c) => {
+ const sessionID = c.req.valid("param").id
+ const session = await Session.get(sessionID)
+ return c.json(session)
+ },
+ )
+ .get(
+ "/session/:id/children",
+ describeRoute({
+ description: "Get a session's children",
+ operationId: "session.children",
+ responses: {
+ 200: {
+ description: "List of children",
+ content: {
+ "application/json": {
+ schema: resolver(Session.Info.array()),
+ },
},
},
},
- },
- }),
- validator(
- "param",
- z.object({
- id: z.string(),
}),
- ),
- async (c) => {
- const sessionID = c.req.valid("param").id
- const session = await Session.children(sessionID)
- return c.json(session)
- },
- )
- .post(
- "/session",
- describeRoute({
- description: "Create a new session",
- operationId: "session.create",
- responses: {
- ...ERRORS,
- 200: {
- description: "Successfully created session",
- content: {
- "application/json": {
- schema: resolver(Session.Info),
+ validator(
+ "param",
+ z.object({
+ id: z.string(),
+ }),
+ ),
+ async (c) => {
+ const sessionID = c.req.valid("param").id
+ const session = await Session.children(sessionID)
+ return c.json(session)
+ },
+ )
+ .post(
+ "/session",
+ describeRoute({
+ description: "Create a new session",
+ operationId: "session.create",
+ responses: {
+ ...ERRORS,
+ 200: {
+ description: "Successfully created session",
+ content: {
+ "application/json": {
+ schema: resolver(Session.Info),
+ },
},
},
},
+ }),
+ validator(
+ "json",
+ z
+ .object({
+ parentID: z.string().optional(),
+ title: z.string().optional(),
+ })
+ .optional(),
+ ),
+ async (c) => {
+ const body = c.req.valid("json") ?? {}
+ const session = await Session.create(body.parentID, body.title)
+ return c.json(session)
},
- }),
- validator(
- "json",
- z
- .object({
- parentID: z.string().optional(),
- title: z.string().optional(),
- })
- .optional(),
- ),
- async (c) => {
- const body = c.req.valid("json") ?? {}
- const session = await Session.create(body.parentID, body.title)
- return c.json(session)
- },
- )
- .delete(
- "/session/:id",
- describeRoute({
- description: "Delete a session and all its data",
- operationId: "session.delete",
- responses: {
- 200: {
- description: "Successfully deleted session",
- content: {
- "application/json": {
- schema: resolver(z.boolean()),
+ )
+ .delete(
+ "/session/:id",
+ describeRoute({
+ description: "Delete a session and all its data",
+ operationId: "session.delete",
+ responses: {
+ 200: {
+ description: "Successfully deleted session",
+ content: {
+ "application/json": {
+ schema: resolver(z.boolean()),
+ },
},
},
},
- },
- }),
- validator(
- "param",
- z.object({
- id: z.string(),
}),
- ),
- async (c) => {
- await Session.remove(c.req.valid("param").id)
- return c.json(true)
- },
- )
- .patch(
- "/session/:id",
- describeRoute({
- description: "Update session properties",
- operationId: "session.update",
- responses: {
- 200: {
- description: "Successfully updated session",
- content: {
- "application/json": {
- schema: resolver(Session.Info),
+ validator(
+ "param",
+ z.object({
+ id: z.string(),
+ }),
+ ),
+ async (c) => {
+ await Session.remove(c.req.valid("param").id)
+ return c.json(true)
+ },
+ )
+ .patch(
+ "/session/:id",
+ describeRoute({
+ description: "Update session properties",
+ operationId: "session.update",
+ responses: {
+ 200: {
+ description: "Successfully updated session",
+ content: {
+ "application/json": {
+ schema: resolver(Session.Info),
+ },
},
},
},
- },
- }),
- validator(
- "param",
- z.object({
- id: z.string(),
}),
- ),
- validator(
- "json",
- z.object({
- title: z.string().optional(),
- }),
- ),
- async (c) => {
- const sessionID = c.req.valid("param").id
- const updates = c.req.valid("json")
+ validator(
+ "param",
+ z.object({
+ id: z.string(),
+ }),
+ ),
+ validator(
+ "json",
+ z.object({
+ title: z.string().optional(),
+ }),
+ ),
+ async (c) => {
+ const sessionID = c.req.valid("param").id
+ const updates = c.req.valid("json")
- const updatedSession = await Session.update(sessionID, (session) => {
- if (updates.title !== undefined) {
- session.title = updates.title
- }
- })
+ const updatedSession = await Session.update(sessionID, (session) => {
+ if (updates.title !== undefined) {
+ session.title = updates.title
+ }
+ })
- return c.json(updatedSession)
- },
- )
- .post(
- "/session/:id/init",
- describeRoute({
- description: "Analyze the app and create an AGENTS.md file",
- operationId: "session.init",
- responses: {
- 200: {
- description: "200",
- content: {
- "application/json": {
- schema: resolver(z.boolean()),
+ return c.json(updatedSession)
+ },
+ )
+ .post(
+ "/session/:id/init",
+ describeRoute({
+ description: "Analyze the app and create an AGENTS.md file",
+ operationId: "session.init",
+ responses: {
+ 200: {
+ description: "200",
+ content: {
+ "application/json": {
+ schema: resolver(z.boolean()),
+ },
},
},
},
- },
- }),
- validator(
- "param",
- z.object({
- id: z.string().meta({ description: "Session ID" }),
- }),
- ),
- validator(
- "json",
- z.object({
- messageID: z.string(),
- providerID: z.string(),
- modelID: z.string(),
}),
- ),
- async (c) => {
- const sessionID = c.req.valid("param").id
- const body = c.req.valid("json")
- await Session.initialize({ ...body, sessionID })
- return c.json(true)
- },
- )
- .post(
- "/session/:id/abort",
- describeRoute({
- description: "Abort a session",
- operationId: "session.abort",
- responses: {
- 200: {
- description: "Aborted session",
- content: {
- "application/json": {
- schema: resolver(z.boolean()),
+ validator(
+ "param",
+ z.object({
+ id: z.string().meta({ description: "Session ID" }),
+ }),
+ ),
+ validator(
+ "json",
+ z.object({
+ messageID: z.string(),
+ providerID: z.string(),
+ modelID: z.string(),
+ }),
+ ),
+ async (c) => {
+ const sessionID = c.req.valid("param").id
+ const body = c.req.valid("json")
+ await Session.initialize({ ...body, sessionID })
+ return c.json(true)
+ },
+ )
+ .post(
+ "/session/:id/abort",
+ describeRoute({
+ description: "Abort a session",
+ operationId: "session.abort",
+ responses: {
+ 200: {
+ description: "Aborted session",
+ content: {
+ "application/json": {
+ schema: resolver(z.boolean()),
+ },
},
},
},
- },
- }),
- validator(
- "param",
- z.object({
- id: z.string(),
}),
- ),
- async (c) => {
- return c.json(SessionPrompt.abort(c.req.valid("param").id))
- },
- )
- .post(
- "/session/:id/share",
- describeRoute({
- description: "Share a session",
- operationId: "session.share",
- responses: {
- 200: {
- description: "Successfully shared session",
- content: {
- "application/json": {
- schema: resolver(Session.Info),
+ validator(
+ "param",
+ z.object({
+ id: z.string(),
+ }),
+ ),
+ async (c) => {
+ return c.json(SessionPrompt.abort(c.req.valid("param").id))
+ },
+ )
+ .post(
+ "/session/:id/share",
+ describeRoute({
+ description: "Share a session",
+ operationId: "session.share",
+ responses: {
+ 200: {
+ description: "Successfully shared session",
+ content: {
+ "application/json": {
+ schema: resolver(Session.Info),
+ },
},
},
},
- },
- }),
- validator(
- "param",
- z.object({
- id: z.string(),
}),
- ),
- async (c) => {
- const id = c.req.valid("param").id
- await Session.share(id)
- const session = await Session.get(id)
- return c.json(session)
- },
- )
- .delete(
- "/session/:id/share",
- describeRoute({
- description: "Unshare the session",
- operationId: "session.unshare",
- responses: {
- 200: {
- description: "Successfully unshared session",
- content: {
- "application/json": {
- schema: resolver(Session.Info),
+ validator(
+ "param",
+ z.object({
+ id: z.string(),
+ }),
+ ),
+ async (c) => {
+ const id = c.req.valid("param").id
+ await Session.share(id)
+ const session = await Session.get(id)
+ return c.json(session)
+ },
+ )
+ .delete(
+ "/session/:id/share",
+ describeRoute({
+ description: "Unshare the session",
+ operationId: "session.unshare",
+ responses: {
+ 200: {
+ description: "Successfully unshared session",
+ content: {
+ "application/json": {
+ schema: resolver(Session.Info),
+ },
},
},
},
- },
- }),
- validator(
- "param",
- z.object({
- id: z.string(),
}),
- ),
- async (c) => {
- const id = c.req.valid("param").id
- await Session.unshare(id)
- const session = await Session.get(id)
- return c.json(session)
- },
- )
- .post(
- "/session/:id/summarize",
- describeRoute({
- description: "Summarize the session",
- operationId: "session.summarize",
- responses: {
- 200: {
- description: "Summarized session",
- content: {
- "application/json": {
- schema: resolver(z.boolean()),
+ validator(
+ "param",
+ z.object({
+ id: z.string(),
+ }),
+ ),
+ async (c) => {
+ const id = c.req.valid("param").id
+ await Session.unshare(id)
+ const session = await Session.get(id)
+ return c.json(session)
+ },
+ )
+ .post(
+ "/session/:id/summarize",
+ describeRoute({
+ description: "Summarize the session",
+ operationId: "session.summarize",
+ responses: {
+ 200: {
+ description: "Summarized session",
+ content: {
+ "application/json": {
+ schema: resolver(z.boolean()),
+ },
},
},
},
- },
- }),
- validator(
- "param",
- z.object({
- id: z.string().meta({ description: "Session ID" }),
- }),
- ),
- validator(
- "json",
- z.object({
- providerID: z.string(),
- modelID: z.string(),
}),
- ),
- async (c) => {
- const id = c.req.valid("param").id
- const body = c.req.valid("json")
- await SessionCompaction.run({ ...body, sessionID: id })
- return c.json(true)
- },
- )
- .get(
- "/session/:id/message",
- describeRoute({
- description: "List messages for a session",
- operationId: "session.messages",
- responses: {
- 200: {
- description: "List of messages",
- content: {
- "application/json": {
- schema: resolver(MessageV2.WithParts.array()),
+ validator(
+ "param",
+ z.object({
+ id: z.string().meta({ description: "Session ID" }),
+ }),
+ ),
+ validator(
+ "json",
+ z.object({
+ providerID: z.string(),
+ modelID: z.string(),
+ }),
+ ),
+ async (c) => {
+ const id = c.req.valid("param").id
+ const body = c.req.valid("json")
+ await SessionCompaction.run({ ...body, sessionID: id })
+ return c.json(true)
+ },
+ )
+ .get(
+ "/session/:id/message",
+ describeRoute({
+ description: "List messages for a session",
+ operationId: "session.messages",
+ responses: {
+ 200: {
+ description: "List of messages",
+ content: {
+ "application/json": {
+ schema: resolver(MessageV2.WithParts.array()),
+ },
},
},
},
- },
- }),
- validator(
- "param",
- z.object({
- id: z.string().meta({ description: "Session ID" }),
}),
- ),
- async (c) => {
- const messages = await Session.messages(c.req.valid("param").id)
- return c.json(messages)
- },
- )
- .get(
- "/session/:id/message/:messageID",
- describeRoute({
- description: "Get a message from a session",
- operationId: "session.message",
- responses: {
- 200: {
- description: "Message",
- content: {
- "application/json": {
- schema: resolver(
- z.object({
- info: MessageV2.Info,
- parts: MessageV2.Part.array(),
- }),
- ),
+ validator(
+ "param",
+ z.object({
+ id: z.string().meta({ description: "Session ID" }),
+ }),
+ ),
+ async (c) => {
+ const messages = await Session.messages(c.req.valid("param").id)
+ return c.json(messages)
+ },
+ )
+ .get(
+ "/session/:id/message/:messageID",
+ describeRoute({
+ description: "Get a message from a session",
+ operationId: "session.message",
+ responses: {
+ 200: {
+ description: "Message",
+ content: {
+ "application/json": {
+ schema: resolver(
+ z.object({
+ info: MessageV2.Info,
+ parts: MessageV2.Part.array(),
+ }),
+ ),
+ },
},
},
},
- },
- }),
- validator(
- "param",
- z.object({
- id: z.string().meta({ description: "Session ID" }),
- messageID: z.string().meta({ description: "Message ID" }),
}),
- ),
- async (c) => {
- const params = c.req.valid("param")
- const message = await Session.getMessage(params.id, params.messageID)
- return c.json(message)
- },
- )
- .post(
- "/session/:id/message",
- describeRoute({
- description: "Create and send a new message to a session",
- operationId: "session.prompt",
- responses: {
- 200: {
- description: "Created message",
- content: {
- "application/json": {
- schema: resolver(
- z.object({
- info: MessageV2.Assistant,
- parts: MessageV2.Part.array(),
- }),
- ),
+ validator(
+ "param",
+ z.object({
+ id: z.string().meta({ description: "Session ID" }),
+ messageID: z.string().meta({ description: "Message ID" }),
+ }),
+ ),
+ async (c) => {
+ const params = c.req.valid("param")
+ const message = await Session.getMessage(params.id, params.messageID)
+ return c.json(message)
+ },
+ )
+ .post(
+ "/session/:id/message",
+ describeRoute({
+ description: "Create and send a new message to a session",
+ operationId: "session.prompt",
+ responses: {
+ 200: {
+ description: "Created message",
+ content: {
+ "application/json": {
+ schema: resolver(
+ z.object({
+ info: MessageV2.Assistant,
+ parts: MessageV2.Part.array(),
+ }),
+ ),
+ },
},
},
},
- },
- }),
- validator(
- "param",
- z.object({
- id: z.string().meta({ description: "Session ID" }),
}),
- ),
- validator("json", SessionPrompt.PromptInput.omit({ sessionID: true })),
- async (c) => {
- const sessionID = c.req.valid("param").id
- const body = c.req.valid("json")
- const msg = await SessionPrompt.prompt({ ...body, sessionID })
- return c.json(msg)
- },
- )
- .post(
- "/session/:id/command",
- describeRoute({
- description: "Send a new command to a session",
- operationId: "session.command",
- responses: {
- 200: {
- description: "Created message",
- content: {
- "application/json": {
- schema: resolver(
- z.object({
- info: MessageV2.Assistant,
- parts: MessageV2.Part.array(),
- }),
- ),
+ validator(
+ "param",
+ z.object({
+ id: z.string().meta({ description: "Session ID" }),
+ }),
+ ),
+ validator("json", SessionPrompt.PromptInput.omit({ sessionID: true })),
+ async (c) => {
+ const sessionID = c.req.valid("param").id
+ const body = c.req.valid("json")
+ const msg = await SessionPrompt.prompt({ ...body, sessionID })
+ return c.json(msg)
+ },
+ )
+ .post(
+ "/session/:id/command",
+ describeRoute({
+ description: "Send a new command to a session",
+ operationId: "session.command",
+ responses: {
+ 200: {
+ description: "Created message",
+ content: {
+ "application/json": {
+ schema: resolver(
+ z.object({
+ info: MessageV2.Assistant,
+ parts: MessageV2.Part.array(),
+ }),
+ ),
+ },
},
},
},
- },
- }),
- validator(
- "param",
- z.object({
- id: z.string().meta({ description: "Session ID" }),
}),
- ),
- validator("json", SessionPrompt.CommandInput.omit({ sessionID: true })),
- async (c) => {
- const sessionID = c.req.valid("param").id
- const body = c.req.valid("json")
- const msg = await SessionPrompt.command({ ...body, sessionID })
- return c.json(msg)
- },
- )
- .post(
- "/session/:id/shell",
- describeRoute({
- description: "Run a shell command",
- operationId: "session.shell",
- responses: {
- 200: {
- description: "Created message",
- content: {
- "application/json": {
- schema: resolver(MessageV2.Assistant),
+ validator(
+ "param",
+ z.object({
+ id: z.string().meta({ description: "Session ID" }),
+ }),
+ ),
+ validator("json", SessionPrompt.CommandInput.omit({ sessionID: true })),
+ async (c) => {
+ const sessionID = c.req.valid("param").id
+ const body = c.req.valid("json")
+ const msg = await SessionPrompt.command({ ...body, sessionID })
+ return c.json(msg)
+ },
+ )
+ .post(
+ "/session/:id/shell",
+ describeRoute({
+ description: "Run a shell command",
+ operationId: "session.shell",
+ responses: {
+ 200: {
+ description: "Created message",
+ content: {
+ "application/json": {
+ schema: resolver(MessageV2.Assistant),
+ },
},
},
},
- },
- }),
- validator(
- "param",
- z.object({
- id: z.string().meta({ description: "Session ID" }),
}),
- ),
- validator("json", SessionPrompt.ShellInput.omit({ sessionID: true })),
- async (c) => {
- const sessionID = c.req.valid("param").id
- const body = c.req.valid("json")
- const msg = await SessionPrompt.shell({ ...body, sessionID })
- return c.json(msg)
- },
- )
- .post(
- "/session/:id/revert",
- describeRoute({
- description: "Revert a message",
- operationId: "session.revert",
- responses: {
- 200: {
- description: "Updated session",
- content: {
- "application/json": {
- schema: resolver(Session.Info),
+ validator(
+ "param",
+ z.object({
+ id: z.string().meta({ description: "Session ID" }),
+ }),
+ ),
+ validator("json", SessionPrompt.ShellInput.omit({ sessionID: true })),
+ async (c) => {
+ const sessionID = c.req.valid("param").id
+ const body = c.req.valid("json")
+ const msg = await SessionPrompt.shell({ ...body, sessionID })
+ return c.json(msg)
+ },
+ )
+ .post(
+ "/session/:id/revert",
+ describeRoute({
+ description: "Revert a message",
+ operationId: "session.revert",
+ responses: {
+ 200: {
+ description: "Updated session",
+ content: {
+ "application/json": {
+ schema: resolver(Session.Info),
+ },
},
},
},
- },
- }),
- validator(
- "param",
- z.object({
- id: z.string(),
}),
- ),
- validator("json", SessionRevert.RevertInput.omit({ sessionID: true })),
- async (c) => {
- const id = c.req.valid("param").id
- log.info("revert", c.req.valid("json"))
- const session = await SessionRevert.revert({ sessionID: id, ...c.req.valid("json") })
- return c.json(session)
- },
- )
- .post(
- "/session/:id/unrevert",
- describeRoute({
- description: "Restore all reverted messages",
- operationId: "session.unrevert",
- responses: {
- 200: {
- description: "Updated session",
- content: {
- "application/json": {
- schema: resolver(Session.Info),
+ validator(
+ "param",
+ z.object({
+ id: z.string(),
+ }),
+ ),
+ validator("json", SessionRevert.RevertInput.omit({ sessionID: true })),
+ async (c) => {
+ const id = c.req.valid("param").id
+ log.info("revert", c.req.valid("json"))
+ const session = await SessionRevert.revert({ sessionID: id, ...c.req.valid("json") })
+ return c.json(session)
+ },
+ )
+ .post(
+ "/session/:id/unrevert",
+ describeRoute({
+ description: "Restore all reverted messages",
+ operationId: "session.unrevert",
+ responses: {
+ 200: {
+ description: "Updated session",
+ content: {
+ "application/json": {
+ schema: resolver(Session.Info),
+ },
},
},
},
- },
- }),
- validator(
- "param",
- z.object({
- id: z.string(),
}),
- ),
- async (c) => {
- const id = c.req.valid("param").id
- const session = await SessionRevert.unrevert({ sessionID: id })
- return c.json(session)
- },
- )
- .post(
- "/session/:id/permissions/:permissionID",
- describeRoute({
- description: "Respond to a permission request",
- responses: {
- 200: {
- description: "Permission processed successfully",
- content: {
- "application/json": {
- schema: resolver(z.boolean()),
+ validator(
+ "param",
+ z.object({
+ id: z.string(),
+ }),
+ ),
+ async (c) => {
+ const id = c.req.valid("param").id
+ const session = await SessionRevert.unrevert({ sessionID: id })
+ return c.json(session)
+ },
+ )
+ .post(
+ "/session/:id/permissions/:permissionID",
+ describeRoute({
+ description: "Respond to a permission request",
+ responses: {
+ 200: {
+ description: "Permission processed successfully",
+ content: {
+ "application/json": {
+ schema: resolver(z.boolean()),
+ },
},
},
},
- },
- }),
- validator(
- "param",
- z.object({
- id: z.string(),
- permissionID: z.string(),
}),
- ),
- validator("json", z.object({ response: Permission.Response })),
- async (c) => {
- const params = c.req.valid("param")
- const id = params.id
- const permissionID = params.permissionID
- Permission.respond({ sessionID: id, permissionID, response: c.req.valid("json").response })
- return c.json(true)
- },
- )
- .get(
- "/command",
- describeRoute({
- description: "List all commands",
- operationId: "command.list",
- responses: {
- 200: {
- description: "List of commands",
- content: {
- "application/json": {
- schema: resolver(Command.Info.array()),
+ validator(
+ "param",
+ z.object({
+ id: z.string(),
+ permissionID: z.string(),
+ }),
+ ),
+ validator("json", z.object({ response: Permission.Response })),
+ async (c) => {
+ const params = c.req.valid("param")
+ const id = params.id
+ const permissionID = params.permissionID
+ Permission.respond({ sessionID: id, permissionID, response: c.req.valid("json").response })
+ return c.json(true)
+ },
+ )
+ .get(
+ "/command",
+ describeRoute({
+ description: "List all commands",
+ operationId: "command.list",
+ responses: {
+ 200: {
+ description: "List of commands",
+ content: {
+ "application/json": {
+ schema: resolver(Command.Info.array()),
+ },
},
},
},
+ }),
+ async (c) => {
+ const commands = await Command.list()
+ return c.json(commands)
},
- }),
- async (c) => {
- const commands = await Command.list()
- return c.json(commands)
- },
- )
- .get(
- "/config/providers",
- describeRoute({
- description: "List all providers",
- operationId: "config.providers",
- responses: {
- 200: {
- description: "List of providers",
- content: {
- "application/json": {
- schema: resolver(
- z.object({
- providers: ModelsDev.Provider.array(),
- default: z.record(z.string(), z.string()),
- }),
- ),
+ )
+ .get(
+ "/config/providers",
+ describeRoute({
+ description: "List all providers",
+ operationId: "config.providers",
+ responses: {
+ 200: {
+ description: "List of providers",
+ content: {
+ "application/json": {
+ schema: resolver(
+ z.object({
+ providers: ModelsDev.Provider.array(),
+ default: z.record(z.string(), z.string()),
+ }),
+ ),
+ },
},
},
},
+ }),
+ async (c) => {
+ const providers = await Provider.list().then((x) => mapValues(x, (item) => item.info))
+ return c.json({
+ providers: Object.values(providers),
+ default: mapValues(providers, (item) => Provider.sort(Object.values(item.models))[0].id),
+ })
},
- }),
- async (c) => {
- const providers = await Provider.list().then((x) => mapValues(x, (item) => item.info))
- return c.json({
- providers: Object.values(providers),
- default: mapValues(providers, (item) => Provider.sort(Object.values(item.models))[0].id),
- })
- },
- )
- .get(
- "/find",
- describeRoute({
- description: "Find text in files",
- operationId: "find.text",
- responses: {
- 200: {
- description: "Matches",
- content: {
- "application/json": {
- schema: resolver(Ripgrep.Match.shape.data.array()),
+ )
+ .get(
+ "/find",
+ describeRoute({
+ description: "Find text in files",
+ operationId: "find.text",
+ responses: {
+ 200: {
+ description: "Matches",
+ content: {
+ "application/json": {
+ schema: resolver(Ripgrep.Match.shape.data.array()),
+ },
},
},
},
- },
- }),
- validator(
- "query",
- z.object({
- pattern: z.string(),
}),
- ),
- async (c) => {
- const pattern = c.req.valid("query").pattern
- const result = await Ripgrep.search({
- cwd: Instance.directory,
- pattern,
- limit: 10,
- })
- return c.json(result)
- },
- )
- .get(
- "/find/file",
- describeRoute({
- description: "Find files",
- operationId: "find.files",
- responses: {
- 200: {
- description: "File paths",
- content: {
- "application/json": {
- schema: resolver(z.string().array()),
+ validator(
+ "query",
+ z.object({
+ pattern: z.string(),
+ }),
+ ),
+ async (c) => {
+ const pattern = c.req.valid("query").pattern
+ const result = await Ripgrep.search({
+ cwd: Instance.directory,
+ pattern,
+ limit: 10,
+ })
+ return c.json(result)
+ },
+ )
+ .get(
+ "/find/file",
+ describeRoute({
+ description: "Find files",
+ operationId: "find.files",
+ responses: {
+ 200: {
+ description: "File paths",
+ content: {
+ "application/json": {
+ schema: resolver(z.string().array()),
+ },
},
},
},
- },
- }),
- validator(
- "query",
- z.object({
- query: z.string(),
}),
- ),
- async (c) => {
- const query = c.req.valid("query").query
- const result = await Ripgrep.files({
- cwd: Instance.directory,
- query,
- limit: 10,
- })
- return c.json(result)
- },
- )
- .get(
- "/find/symbol",
- describeRoute({
- description: "Find workspace symbols",
- operationId: "find.symbols",
- responses: {
- 200: {
- description: "Symbols",
- content: {
- "application/json": {
- schema: resolver(LSP.Symbol.array()),
+ validator(
+ "query",
+ z.object({
+ query: z.string(),
+ }),
+ ),
+ async (c) => {
+ const query = c.req.valid("query").query
+ const result = await Ripgrep.files({
+ cwd: Instance.directory,
+ query,
+ limit: 10,
+ })
+ return c.json(result)
+ },
+ )
+ .get(
+ "/find/symbol",
+ describeRoute({
+ description: "Find workspace symbols",
+ operationId: "find.symbols",
+ responses: {
+ 200: {
+ description: "Symbols",
+ content: {
+ "application/json": {
+ schema: resolver(LSP.Symbol.array()),
+ },
},
},
},
- },
- }),
- validator(
- "query",
- z.object({
- query: z.string(),
}),
- ),
- async (c) => {
- const query = c.req.valid("query").query
- const result = await LSP.workspaceSymbol(query)
- return c.json(result)
- },
- )
- .get(
- "/file",
- describeRoute({
- description: "List files and directories",
- operationId: "file.list",
- responses: {
- 200: {
- description: "Files and directories",
- content: {
- "application/json": {
- schema: resolver(File.Node.array()),
+ validator(
+ "query",
+ z.object({
+ query: z.string(),
+ }),
+ ),
+ async (c) => {
+ const query = c.req.valid("query").query
+ const result = await LSP.workspaceSymbol(query)
+ return c.json(result)
+ },
+ )
+ .get(
+ "/file",
+ describeRoute({
+ description: "List files and directories",
+ operationId: "file.list",
+ responses: {
+ 200: {
+ description: "Files and directories",
+ content: {
+ "application/json": {
+ schema: resolver(File.Node.array()),
+ },
},
},
},
- },
- }),
- validator(
- "query",
- z.object({
- path: z.string(),
}),
- ),
- async (c) => {
- const path = c.req.valid("query").path
- const content = await File.list(path)
- return c.json(content)
- },
- )
- .get(
- "/file/content",
- describeRoute({
- description: "Read a file",
- operationId: "file.read",
- responses: {
- 200: {
- description: "File content",
- content: {
- "application/json": {
- schema: resolver(File.Content),
+ validator(
+ "query",
+ z.object({
+ path: z.string(),
+ }),
+ ),
+ async (c) => {
+ const path = c.req.valid("query").path
+ const content = await File.list(path)
+ return c.json(content)
+ },
+ )
+ .get(
+ "/file/content",
+ describeRoute({
+ description: "Read a file",
+ operationId: "file.read",
+ responses: {
+ 200: {
+ description: "File content",
+ content: {
+ "application/json": {
+ schema: resolver(File.Content),
+ },
},
},
},
- },
- }),
- validator(
- "query",
- z.object({
- path: z.string(),
}),
- ),
- async (c) => {
- const path = c.req.valid("query").path
- const content = await File.read(path)
- return c.json(content)
- },
- )
- .get(
- "/file/status",
- describeRoute({
- description: "Get file status",
- operationId: "file.status",
- responses: {
- 200: {
- description: "File status",
- content: {
- "application/json": {
- schema: resolver(File.Info.array()),
+ validator(
+ "query",
+ z.object({
+ path: z.string(),
+ }),
+ ),
+ async (c) => {
+ const path = c.req.valid("query").path
+ const content = await File.read(path)
+ return c.json(content)
+ },
+ )
+ .get(
+ "/file/status",
+ describeRoute({
+ description: "Get file status",
+ operationId: "file.status",
+ responses: {
+ 200: {
+ description: "File status",
+ content: {
+ "application/json": {
+ schema: resolver(File.Info.array()),
+ },
},
},
},
+ }),
+ async (c) => {
+ const content = await File.status()
+ return c.json(content)
},
- }),
- async (c) => {
- const content = await File.status()
- return c.json(content)
- },
- )
- .post(
- "/log",
- describeRoute({
- description: "Write a log entry to the server logs",
- operationId: "app.log",
- responses: {
- 200: {
- description: "Log entry written successfully",
- content: {
- "application/json": {
- schema: resolver(z.boolean()),
+ )
+ .post(
+ "/log",
+ describeRoute({
+ description: "Write a log entry to the server logs",
+ operationId: "app.log",
+ responses: {
+ 200: {
+ description: "Log entry written successfully",
+ content: {
+ "application/json": {
+ schema: resolver(z.boolean()),
+ },
},
},
},
- },
- }),
- validator(
- "json",
- z.object({
- service: z.string().meta({ description: "Service name for the log entry" }),
- level: z.enum(["debug", "info", "error", "warn"]).meta({ description: "Log level" }),
- message: z.string().meta({ description: "Log message" }),
- extra: z
- .record(z.string(), z.any())
- .optional()
- .meta({ description: "Additional metadata for the log entry" }),
}),
- ),
- async (c) => {
- const { service, level, message, extra } = c.req.valid("json")
- const logger = Log.create({ service })
+ validator(
+ "json",
+ z.object({
+ service: z.string().meta({ description: "Service name for the log entry" }),
+ level: z.enum(["debug", "info", "error", "warn"]).meta({ description: "Log level" }),
+ message: z.string().meta({ description: "Log message" }),
+ extra: z
+ .record(z.string(), z.any())
+ .optional()
+ .meta({ description: "Additional metadata for the log entry" }),
+ }),
+ ),
+ async (c) => {
+ const { service, level, message, extra } = c.req.valid("json")
+ const logger = Log.create({ service })
- switch (level) {
- case "debug":
- logger.debug(message, extra)
- break
- case "info":
- logger.info(message, extra)
- break
- case "error":
- logger.error(message, extra)
- break
- case "warn":
- logger.warn(message, extra)
- break
- }
+ switch (level) {
+ case "debug":
+ logger.debug(message, extra)
+ break
+ case "info":
+ logger.info(message, extra)
+ break
+ case "error":
+ logger.error(message, extra)
+ break
+ case "warn":
+ logger.warn(message, extra)
+ break
+ }
- return c.json(true)
- },
- )
- .get(
- "/agent",
- describeRoute({
- description: "List all agents",
- operationId: "app.agents",
- responses: {
- 200: {
- description: "List of agents",
- content: {
- "application/json": {
- schema: resolver(Agent.Info.array()),
+ return c.json(true)
+ },
+ )
+ .get(
+ "/agent",
+ describeRoute({
+ description: "List all agents",
+ operationId: "app.agents",
+ responses: {
+ 200: {
+ description: "List of agents",
+ content: {
+ "application/json": {
+ schema: resolver(Agent.Info.array()),
+ },
},
},
},
+ }),
+ async (c) => {
+ const modes = await Agent.list()
+ return c.json(modes)
},
- }),
- async (c) => {
- const modes = await Agent.list()
- return c.json(modes)
- },
- )
- .post(
- "/tui/append-prompt",
- describeRoute({
- description: "Append prompt to the TUI",
- operationId: "tui.appendPrompt",
- responses: {
- 200: {
- description: "Prompt processed successfully",
- content: {
- "application/json": {
- schema: resolver(z.boolean()),
+ )
+ .post(
+ "/tui/append-prompt",
+ describeRoute({
+ description: "Append prompt to the TUI",
+ operationId: "tui.appendPrompt",
+ responses: {
+ 200: {
+ description: "Prompt processed successfully",
+ content: {
+ "application/json": {
+ schema: resolver(z.boolean()),
+ },
},
},
},
- },
- }),
- validator(
- "json",
- z.object({
- text: z.string(),
}),
- ),
- async (c) => c.json(await callTui(c)),
- )
- .post(
- "/tui/open-help",
- describeRoute({
- description: "Open the help dialog",
- operationId: "tui.openHelp",
- responses: {
- 200: {
- description: "Help dialog opened successfully",
- content: {
- "application/json": {
- schema: resolver(z.boolean()),
+ validator(
+ "json",
+ z.object({
+ text: z.string(),
+ }),
+ ),
+ async (c) => c.json(await callTui(c)),
+ )
+ .post(
+ "/tui/open-help",
+ describeRoute({
+ description: "Open the help dialog",
+ operationId: "tui.openHelp",
+ responses: {
+ 200: {
+ description: "Help dialog opened successfully",
+ content: {
+ "application/json": {
+ schema: resolver(z.boolean()),
+ },
},
},
},
- },
- }),
- async (c) => c.json(await callTui(c)),
- )
- .post(
- "/tui/open-sessions",
- describeRoute({
- description: "Open the session dialog",
- operationId: "tui.openSessions",
- responses: {
- 200: {
- description: "Session dialog opened successfully",
- content: {
- "application/json": {
- schema: resolver(z.boolean()),
+ }),
+ async (c) => c.json(await callTui(c)),
+ )
+ .post(
+ "/tui/open-sessions",
+ describeRoute({
+ description: "Open the session dialog",
+ operationId: "tui.openSessions",
+ responses: {
+ 200: {
+ description: "Session dialog opened successfully",
+ content: {
+ "application/json": {
+ schema: resolver(z.boolean()),
+ },
},
},
},
- },
- }),
- async (c) => c.json(await callTui(c)),
- )
- .post(
- "/tui/open-themes",
- describeRoute({
- description: "Open the theme dialog",
- operationId: "tui.openThemes",
- responses: {
- 200: {
- description: "Theme dialog opened successfully",
- content: {
- "application/json": {
- schema: resolver(z.boolean()),
+ }),
+ async (c) => c.json(await callTui(c)),
+ )
+ .post(
+ "/tui/open-themes",
+ describeRoute({
+ description: "Open the theme dialog",
+ operationId: "tui.openThemes",
+ responses: {
+ 200: {
+ description: "Theme dialog opened successfully",
+ content: {
+ "application/json": {
+ schema: resolver(z.boolean()),
+ },
},
},
},
- },
- }),
- async (c) => c.json(await callTui(c)),
- )
- .post(
- "/tui/open-models",
- describeRoute({
- description: "Open the model dialog",
- operationId: "tui.openModels",
- responses: {
- 200: {
- description: "Model dialog opened successfully",
- content: {
- "application/json": {
- schema: resolver(z.boolean()),
+ }),
+ async (c) => c.json(await callTui(c)),
+ )
+ .post(
+ "/tui/open-models",
+ describeRoute({
+ description: "Open the model dialog",
+ operationId: "tui.openModels",
+ responses: {
+ 200: {
+ description: "Model dialog opened successfully",
+ content: {
+ "application/json": {
+ schema: resolver(z.boolean()),
+ },
},
},
},
- },
- }),
- async (c) => c.json(await callTui(c)),
- )
- .post(
- "/tui/submit-prompt",
- describeRoute({
- description: "Submit the prompt",
- operationId: "tui.submitPrompt",
- responses: {
- 200: {
- description: "Prompt submitted successfully",
- content: {
- "application/json": {
- schema: resolver(z.boolean()),
+ }),
+ async (c) => c.json(await callTui(c)),
+ )
+ .post(
+ "/tui/submit-prompt",
+ describeRoute({
+ description: "Submit the prompt",
+ operationId: "tui.submitPrompt",
+ responses: {
+ 200: {
+ description: "Prompt submitted successfully",
+ content: {
+ "application/json": {
+ schema: resolver(z.boolean()),
+ },
},
},
},
- },
- }),
- async (c) => c.json(await callTui(c)),
- )
- .post(
- "/tui/clear-prompt",
- describeRoute({
- description: "Clear the prompt",
- operationId: "tui.clearPrompt",
- responses: {
- 200: {
- description: "Prompt cleared successfully",
- content: {
- "application/json": {
- schema: resolver(z.boolean()),
+ }),
+ async (c) => c.json(await callTui(c)),
+ )
+ .post(
+ "/tui/clear-prompt",
+ describeRoute({
+ description: "Clear the prompt",
+ operationId: "tui.clearPrompt",
+ responses: {
+ 200: {
+ description: "Prompt cleared successfully",
+ content: {
+ "application/json": {
+ schema: resolver(z.boolean()),
+ },
},
},
},
- },
- }),
- async (c) => c.json(await callTui(c)),
- )
- .post(
- "/tui/execute-command",
- describeRoute({
- description: "Execute a TUI command (e.g. agent_cycle)",
- operationId: "tui.executeCommand",
- responses: {
- 200: {
- description: "Command executed successfully",
- content: {
- "application/json": {
- schema: resolver(z.boolean()),
+ }),
+ async (c) => c.json(await callTui(c)),
+ )
+ .post(
+ "/tui/execute-command",
+ describeRoute({
+ description: "Execute a TUI command (e.g. agent_cycle)",
+ operationId: "tui.executeCommand",
+ responses: {
+ 200: {
+ description: "Command executed successfully",
+ content: {
+ "application/json": {
+ schema: resolver(z.boolean()),
+ },
},
},
},
- },
- }),
- validator(
- "json",
- z.object({
- command: z.string(),
}),
- ),
- async (c) => c.json(await callTui(c)),
- )
- .post(
- "/tui/show-toast",
- describeRoute({
- description: "Show a toast notification in the TUI",
- operationId: "tui.showToast",
- responses: {
- 200: {
- description: "Toast notification shown successfully",
- content: {
- "application/json": {
- schema: resolver(z.boolean()),
+ validator(
+ "json",
+ z.object({
+ command: z.string(),
+ }),
+ ),
+ async (c) => c.json(await callTui(c)),
+ )
+ .post(
+ "/tui/show-toast",
+ describeRoute({
+ description: "Show a toast notification in the TUI",
+ operationId: "tui.showToast",
+ responses: {
+ 200: {
+ description: "Toast notification shown successfully",
+ content: {
+ "application/json": {
+ schema: resolver(z.boolean()),
+ },
},
},
},
- },
- }),
- validator(
- "json",
- z.object({
- title: z.string().optional(),
- message: z.string(),
- variant: z.enum(["info", "success", "warning", "error"]),
}),
- ),
- async (c) => c.json(await callTui(c)),
- )
- .route("/tui/control", TuiRoute)
- .put(
- "/auth/:id",
- describeRoute({
- description: "Set authentication credentials",
- operationId: "auth.set",
- responses: {
- 200: {
- description: "Successfully set authentication credentials",
- content: {
- "application/json": {
- schema: resolver(z.boolean()),
+ validator(
+ "json",
+ z.object({
+ title: z.string().optional(),
+ message: z.string(),
+ variant: z.enum(["info", "success", "warning", "error"]),
+ }),
+ ),
+ async (c) => c.json(await callTui(c)),
+ )
+ .route("/tui/control", TuiRoute)
+ .put(
+ "/auth/:id",
+ describeRoute({
+ description: "Set authentication credentials",
+ operationId: "auth.set",
+ responses: {
+ 200: {
+ description: "Successfully set authentication credentials",
+ content: {
+ "application/json": {
+ schema: resolver(z.boolean()),
+ },
},
},
+ ...ERRORS,
},
- ...ERRORS,
+ }),
+ validator(
+ "param",
+ z.object({
+ id: z.string(),
+ }),
+ ),
+ validator("json", Auth.Info),
+ async (c) => {
+ const id = c.req.valid("param").id
+ const info = c.req.valid("json")
+ await Auth.set(id, info)
+ return c.json(true)
},
- }),
- validator(
- "param",
- z.object({
- id: z.string(),
+ )
+ .get(
+ "/event",
+ describeRoute({
+ description: "Get events",
+ operationId: "event.subscribe",
+ responses: {
+ 200: {
+ description: "Event stream",
+ content: {
+ "text/event-stream": {
+ schema: resolver(
+ Bus.payloads().meta({
+ ref: "Event",
+ }),
+ ),
+ },
+ },
+ },
+ },
}),
+ async (c) => {
+ log.info("event connected")
+ return streamSSE(c, async (stream) => {
+ stream.writeSSE({
+ data: JSON.stringify({
+ type: "server.connected",
+ properties: {},
+ }),
+ })
+ const unsub = Bus.subscribeAll(async (event) => {
+ await stream.writeSSE({
+ data: JSON.stringify(event),
+ })
+ })
+ await new Promise<void>((resolve) => {
+ stream.onAbort(() => {
+ unsub()
+ resolve()
+ log.info("event disconnected")
+ })
+ })
+ })
+ },
),
- validator("json", Auth.Info),
- async (c) => {
- const id = c.req.valid("param").id
- const info = c.req.valid("json")
- await Auth.set(id, info)
- return c.json(true)
- },
- )
+ )
export async function openapi() {
- const result = await generateSpecs(App, {
+ const result = await generateSpecs(App(), {
documentation: {
info: {
title: "opencode",
@@ -1433,7 +1436,7 @@ export namespace Server {
port: opts.port,
hostname: opts.hostname,
idleTimeout: 0,
- fetch: App.fetch,
+ fetch: App().fetch,
})
return server
}
diff --git a/packages/opencode/test/tool/register.test.ts b/packages/opencode/test/tool/register.test.ts
index 834d18984..351eb91d1 100644
--- a/packages/opencode/test/tool/register.test.ts
+++ b/packages/opencode/test/tool/register.test.ts
@@ -31,7 +31,7 @@ describe("HTTP tool registration API", () => {
}
// Register
- const registerRes = await Server.App.fetch(
+ const registerRes = await Server.App().fetch(
makeRequest("POST", "http://localhost:4096/experimental/tool/register", toolSpec),
)
expect(registerRes.status).toBe(200)
@@ -39,13 +39,13 @@ describe("HTTP tool registration API", () => {
expect(ok).toBe(true)
// IDs should include the new tool
- const idsRes = await Server.App.fetch(makeRequest("GET", "http://localhost:4096/experimental/tool/ids"))
+ const idsRes = await Server.App().fetch(makeRequest("GET", "http://localhost:4096/experimental/tool/ids"))
expect(idsRes.status).toBe(200)
const ids = (await idsRes.json()) as string[]
expect(ids).toContain("http-echo")
// List tools for a provider/model and check JSON Schema shape
- const listRes = await Server.App.fetch(
+ const listRes = await Server.App().fetch(
makeRequest("GET", "http://localhost:4096/experimental/tool?provider=openai&model=gpt-4o"),
)
expect(listRes.status).toBe(200)
@@ -105,7 +105,7 @@ describe("Plugin tool.register hook", () => {
expect(allIDs).toContain("from-plugin")
// Also verify via the HTTP surface
- const idsRes = await Server.App.fetch(makeRequest("GET", "http://localhost:4096/experimental/tool/ids"))
+ const idsRes = await Server.App().fetch(makeRequest("GET", "http://localhost:4096/experimental/tool/ids"))
expect(idsRes.status).toBe(200)
const ids = (await idsRes.json()) as string[]
expect(ids).toContain("from-plugin")
@@ -168,7 +168,7 @@ test("Multiple plugins can each register tools", async () => {
expect(ids).toContain("alpha-tool")
expect(ids).toContain("beta-tool")
- const res = await Server.App.fetch(new Request("http://localhost:4096/experimental/tool/ids"))
+ const res = await Server.App().fetch(new Request("http://localhost:4096/experimental/tool/ids"))
expect(res.status).toBe(200)
const httpIds = (await res.json()) as string[]
expect(httpIds).toContain("alpha-tool")
@@ -241,14 +241,14 @@ test("Plugin registers native/local tool with function execution", async () => {
expect(ids).toContain("http-tool-from-same-plugin")
// Verify via HTTP endpoint
- const res = await Server.App.fetch(new Request("http://localhost:4096/experimental/tool/ids"))
+ const res = await Server.App().fetch(new Request("http://localhost:4096/experimental/tool/ids"))
expect(res.status).toBe(200)
const httpIds = (await res.json()) as string[]
expect(httpIds).toContain("my-native-tool")
expect(httpIds).toContain("http-tool-from-same-plugin")
// Get tool details to verify native tool has proper structure
- const toolsRes = await Server.App.fetch(
+ const toolsRes = await Server.App().fetch(
new Request("http://localhost:4096/experimental/tool?provider=anthropic&model=claude"),
)
expect(toolsRes.status).toBe(200)
@@ -290,7 +290,7 @@ test("Plugin without tool.register is handled gracefully", async () => {
const ids = ToolRegistry.ids()
expect(ids).not.toContain("malformed-tool")
- const res = await Server.App.fetch(new Request("http://localhost:4096/experimental/tool/ids"))
+ const res = await Server.App().fetch(new Request("http://localhost:4096/experimental/tool/ids"))
expect(res.status).toBe(200)
const httpIds = (await res.json()) as string[]
expect(httpIds).not.toContain("malformed-tool")
diff --git a/packages/sdk/go/.release-please-manifest.json b/packages/sdk/go/.release-please-manifest.json
index 727e2bea9..f87262aa8 100644
--- a/packages/sdk/go/.release-please-manifest.json
+++ b/packages/sdk/go/.release-please-manifest.json
@@ -1,3 +1,3 @@
{
- ".": "0.14.0"
+ ".": "0.15.0"
}
diff --git a/packages/sdk/go/.stats.yml b/packages/sdk/go/.stats.yml
index 9d47e52e1..f4ae16705 100644
--- a/packages/sdk/go/.stats.yml
+++ b/packages/sdk/go/.stats.yml
@@ -1,4 +1,4 @@
configured_endpoints: 43
-openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/opencode%2Fopencode-0a4165f1eabf826d3092ea6b789aa527048278dcd4bd891f9e5ac890b9bcbb35.yml
-openapi_spec_hash: da60e4fc813eb0f9ac3ab5f112e26bf6
+openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/opencode%2Fopencode-ad911ed0bdbeca62807509f364f25fcafd7a83e0b43e027ec0a85f72b7a4d963.yml
+openapi_spec_hash: 15152513b4246bf4b5f8546fa6f1603f
config_hash: 026ef000d34bf2f930e7b41e77d2d3ff
diff --git a/packages/sdk/go/CHANGELOG.md b/packages/sdk/go/CHANGELOG.md
index 9e13db9e0..f82dffa42 100644
--- a/packages/sdk/go/CHANGELOG.md
+++ b/packages/sdk/go/CHANGELOG.md
@@ -1,5 +1,13 @@
# Changelog
+## 0.15.0 (2025-09-16)
+
+Full Changelog: [v0.14.0...v0.15.0](https://github.com/sst/opencode-sdk-go/compare/v0.14.0...v0.15.0)
+
+### Features
+
+- **api:** api update ([397048f](https://github.com/sst/opencode-sdk-go/commit/397048faca7a1de7a028edd2254a0ad7797b151f))
+
## 0.14.0 (2025-09-14)
Full Changelog: [v0.13.0...v0.14.0](https://github.com/sst/opencode-sdk-go/compare/v0.13.0...v0.14.0)
diff --git a/packages/sdk/go/README.md b/packages/sdk/go/README.md
index 96898209d..39c358371 100644
--- a/packages/sdk/go/README.md
+++ b/packages/sdk/go/README.md
@@ -24,7 +24,7 @@ Or to pin the version:
<!-- x-release-please-start-version -->
```sh
-go get -u 'github.com/sst/[email protected]'
+go get -u 'github.com/sst/[email protected]'
```
<!-- x-release-please-end -->
diff --git a/packages/sdk/go/config.go b/packages/sdk/go/config.go
index d469bdff1..c79de17f0 100644
--- a/packages/sdk/go/config.go
+++ b/packages/sdk/go/config.go
@@ -90,8 +90,9 @@ type Config struct {
// TUI specific settings
Tui ConfigTui `json:"tui"`
// Custom username to display in conversations instead of system username
- Username string `json:"username"`
- JSON configJSON `json:"-"`
+ Username string `json:"username"`
+ Watcher ConfigWatcher `json:"watcher"`
+ JSON configJSON `json:"-"`
}
// configJSON contains the JSON metadata for the struct [Config]
@@ -121,6 +122,7 @@ type configJSON struct {
Tools apijson.Field
Tui apijson.Field
Username apijson.Field
+ Watcher apijson.Field
raw string
ExtraFields map[string]apijson.Field
}
@@ -1772,6 +1774,26 @@ func (r configTuiJSON) RawJSON() string {
return r.raw
}
+type ConfigWatcher struct {
+ Ignore []string `json:"ignore"`
+ JSON configWatcherJSON `json:"-"`
+}
+
+// configWatcherJSON contains the JSON metadata for the struct [ConfigWatcher]
+type configWatcherJSON struct {
+ Ignore apijson.Field
+ raw string
+ ExtraFields map[string]apijson.Field
+}
+
+func (r *ConfigWatcher) UnmarshalJSON(data []byte) (err error) {
+ return apijson.UnmarshalRoot(data, r)
+}
+
+func (r configWatcherJSON) RawJSON() string {
+ return r.raw
+}
+
// Custom keybind configurations
type KeybindsConfig struct {
// Next agent
diff --git a/packages/sdk/go/event.go b/packages/sdk/go/event.go
index 5d3bffcc2..35b4353cf 100644
--- a/packages/sdk/go/event.go
+++ b/packages/sdk/go/event.go
@@ -64,7 +64,9 @@ type EventListResponse struct {
// [EventListResponseEventSessionIdleProperties],
// [EventListResponseEventSessionUpdatedProperties],
// [EventListResponseEventSessionDeletedProperties],
- // [EventListResponseEventSessionErrorProperties], [interface{}].
+ // [EventListResponseEventSessionErrorProperties], [interface{}],
+ // [EventListResponseEventFileWatcherUpdatedProperties],
+ // [EventListResponseEventIdeInstalledProperties].
Properties interface{} `json:"properties,required"`
Type EventListResponseType `json:"type,required"`
JSON eventListResponseJSON `json:"-"`
@@ -107,7 +109,9 @@ func (r *EventListResponse) UnmarshalJSON(data []byte) (err error) {
// [EventListResponseEventPermissionReplied], [EventListResponseEventFileEdited],
// [EventListResponseEventSessionIdle], [EventListResponseEventSessionUpdated],
// [EventListResponseEventSessionDeleted], [EventListResponseEventSessionError],
-// [EventListResponseEventServerConnected].
+// [EventListResponseEventServerConnected],
+// [EventListResponseEventFileWatcherUpdated],
+// [EventListResponseEventIdeInstalled].
func (r EventListResponse) AsUnion() EventListResponseUnion {
return r.union
}
@@ -121,8 +125,10 @@ func (r EventListResponse) AsUnion() EventListResponseUnion {
// [EventListResponseEventPermissionUpdated],
// [EventListResponseEventPermissionReplied], [EventListResponseEventFileEdited],
// [EventListResponseEventSessionIdle], [EventListResponseEventSessionUpdated],
-// [EventListResponseEventSessionDeleted], [EventListResponseEventSessionError] or
-// [EventListResponseEventServerConnected].
+// [EventListResponseEventSessionDeleted], [EventListResponseEventSessionError],
+// [EventListResponseEventServerConnected],
+// [EventListResponseEventFileWatcherUpdated] or
+// [EventListResponseEventIdeInstalled].
type EventListResponseUnion interface {
implementsEventListResponse()
}
@@ -191,6 +197,14 @@ func init() {
TypeFilter: gjson.JSON,
Type: reflect.TypeOf(EventListResponseEventServerConnected{}),
},
+ apijson.UnionVariant{
+ TypeFilter: gjson.JSON,
+ Type: reflect.TypeOf(EventListResponseEventFileWatcherUpdated{}),
+ },
+ apijson.UnionVariant{
+ TypeFilter: gjson.JSON,
+ Type: reflect.TypeOf(EventListResponseEventIdeInstalled{}),
+ },
)
}
@@ -1196,6 +1210,144 @@ func (r EventListResponseEventServerConnectedType) IsKnown() bool {
return false
}
+type EventListResponseEventFileWatcherUpdated struct {
+ Properties EventListResponseEventFileWatcherUpdatedProperties `json:"properties,required"`
+ Type EventListResponseEventFileWatcherUpdatedType `json:"type,required"`
+ JSON eventListResponseEventFileWatcherUpdatedJSON `json:"-"`
+}
+
+// eventListResponseEventFileWatcherUpdatedJSON contains the JSON metadata for the
+// struct [EventListResponseEventFileWatcherUpdated]
+type eventListResponseEventFileWatcherUpdatedJSON struct {
+ Properties apijson.Field
+ Type apijson.Field
+ raw string
+ ExtraFields map[string]apijson.Field
+}
+
+func (r *EventListResponseEventFileWatcherUpdated) UnmarshalJSON(data []byte) (err error) {
+ return apijson.UnmarshalRoot(data, r)
+}
+
+func (r eventListResponseEventFileWatcherUpdatedJSON) RawJSON() string {
+ return r.raw
+}
+
+func (r EventListResponseEventFileWatcherUpdated) implementsEventListResponse() {}
+
+type EventListResponseEventFileWatcherUpdatedProperties struct {
+ Event EventListResponseEventFileWatcherUpdatedPropertiesEvent `json:"event,required"`
+ File string `json:"file,required"`
+ JSON eventListResponseEventFileWatcherUpdatedPropertiesJSON `json:"-"`
+}
+
+// eventListResponseEventFileWatcherUpdatedPropertiesJSON contains the JSON
+// metadata for the struct [EventListResponseEventFileWatcherUpdatedProperties]
+type eventListResponseEventFileWatcherUpdatedPropertiesJSON struct {
+ Event apijson.Field
+ File apijson.Field
+ raw string
+ ExtraFields map[string]apijson.Field
+}
+
+func (r *EventListResponseEventFileWatcherUpdatedProperties) UnmarshalJSON(data []byte) (err error) {
+ return apijson.UnmarshalRoot(data, r)
+}
+
+func (r eventListResponseEventFileWatcherUpdatedPropertiesJSON) RawJSON() string {
+ return r.raw
+}
+
+type EventListResponseEventFileWatcherUpdatedPropertiesEvent string
+
+const (
+ EventListResponseEventFileWatcherUpdatedPropertiesEventAdd EventListResponseEventFileWatcherUpdatedPropertiesEvent = "add"
+ EventListResponseEventFileWatcherUpdatedPropertiesEventChange EventListResponseEventFileWatcherUpdatedPropertiesEvent = "change"
+ EventListResponseEventFileWatcherUpdatedPropertiesEventUnlink EventListResponseEventFileWatcherUpdatedPropertiesEvent = "unlink"
+)
+
+func (r EventListResponseEventFileWatcherUpdatedPropertiesEvent) IsKnown() bool {
+ switch r {
+ case EventListResponseEventFileWatcherUpdatedPropertiesEventAdd, EventListResponseEventFileWatcherUpdatedPropertiesEventChange, EventListResponseEventFileWatcherUpdatedPropertiesEventUnlink:
+ return true
+ }
+ return false
+}
+
+type EventListResponseEventFileWatcherUpdatedType string
+
+const (
+ EventListResponseEventFileWatcherUpdatedTypeFileWatcherUpdated EventListResponseEventFileWatcherUpdatedType = "file.watcher.updated"
+)
+
+func (r EventListResponseEventFileWatcherUpdatedType) IsKnown() bool {
+ switch r {
+ case EventListResponseEventFileWatcherUpdatedTypeFileWatcherUpdated:
+ return true
+ }
+ return false
+}
+
+type EventListResponseEventIdeInstalled struct {
+ Properties EventListResponseEventIdeInstalledProperties `json:"properties,required"`
+ Type EventListResponseEventIdeInstalledType `json:"type,required"`
+ JSON eventListResponseEventIdeInstalledJSON `json:"-"`
+}
+
+// eventListResponseEventIdeInstalledJSON contains the JSON metadata for the struct
+// [EventListResponseEventIdeInstalled]
+type eventListResponseEventIdeInstalledJSON struct {
+ Properties apijson.Field
+ Type apijson.Field
+ raw string
+ ExtraFields map[string]apijson.Field
+}
+
+func (r *EventListResponseEventIdeInstalled) UnmarshalJSON(data []byte) (err error) {
+ return apijson.UnmarshalRoot(data, r)
+}
+
+func (r eventListResponseEventIdeInstalledJSON) RawJSON() string {
+ return r.raw
+}
+
+func (r EventListResponseEventIdeInstalled) implementsEventListResponse() {}
+
+type EventListResponseEventIdeInstalledProperties struct {
+ Ide string `json:"ide,required"`
+ JSON eventListResponseEventIdeInstalledPropertiesJSON `json:"-"`
+}
+
+// eventListResponseEventIdeInstalledPropertiesJSON contains the JSON metadata for
+// the struct [EventListResponseEventIdeInstalledProperties]
+type eventListResponseEventIdeInstalledPropertiesJSON struct {
+ Ide apijson.Field
+ raw string
+ ExtraFields map[string]apijson.Field
+}
+
+func (r *EventListResponseEventIdeInstalledProperties) UnmarshalJSON(data []byte) (err error) {
+ return apijson.UnmarshalRoot(data, r)
+}
+
+func (r eventListResponseEventIdeInstalledPropertiesJSON) RawJSON() string {
+ return r.raw
+}
+
+type EventListResponseEventIdeInstalledType string
+
+const (
+ EventListResponseEventIdeInstalledTypeIdeInstalled EventListResponseEventIdeInstalledType = "ide.installed"
+)
+
+func (r EventListResponseEventIdeInstalledType) IsKnown() bool {
+ switch r {
+ case EventListResponseEventIdeInstalledTypeIdeInstalled:
+ return true
+ }
+ return false
+}
+
type EventListResponseType string
const (
@@ -1214,11 +1366,13 @@ const (
EventListResponseTypeSessionDeleted EventListResponseType = "session.deleted"
EventListResponseTypeSessionError EventListResponseType = "session.error"
EventListResponseTypeServerConnected EventListResponseType = "server.connected"
+ EventListResponseTypeFileWatcherUpdated EventListResponseType = "file.watcher.updated"
+ EventListResponseTypeIdeInstalled EventListResponseType = "ide.installed"
)
func (r EventListResponseType) IsKnown() bool {
switch r {
- case EventListResponseTypeInstallationUpdated, EventListResponseTypeLspClientDiagnostics, EventListResponseTypeMessageUpdated, EventListResponseTypeMessageRemoved, EventListResponseTypeMessagePartUpdated, EventListResponseTypeMessagePartRemoved, EventListResponseTypeSessionCompacted, EventListResponseTypePermissionUpdated, EventListResponseTypePermissionReplied, EventListResponseTypeFileEdited, EventListResponseTypeSessionIdle, EventListResponseTypeSessionUpdated, EventListResponseTypeSessionDeleted, EventListResponseTypeSessionError, EventListResponseTypeServerConnected:
+ case EventListResponseTypeInstallationUpdated, EventListResponseTypeLspClientDiagnostics, EventListResponseTypeMessageUpdated, EventListResponseTypeMessageRemoved, EventListResponseTypeMessagePartUpdated, EventListResponseTypeMessagePartRemoved, EventListResponseTypeSessionCompacted, EventListResponseTypePermissionUpdated, EventListResponseTypePermissionReplied, EventListResponseTypeFileEdited, EventListResponseTypeSessionIdle, EventListResponseTypeSessionUpdated, EventListResponseTypeSessionDeleted, EventListResponseTypeSessionError, EventListResponseTypeServerConnected, EventListResponseTypeFileWatcherUpdated, EventListResponseTypeIdeInstalled:
return true
}
return false
diff --git a/packages/sdk/go/internal/version.go b/packages/sdk/go/internal/version.go
index 870e575ab..1f338c33e 100644
--- a/packages/sdk/go/internal/version.go
+++ b/packages/sdk/go/internal/version.go
@@ -2,4 +2,4 @@
package internal
-const PackageVersion = "0.14.0" // x-release-please-version
+const PackageVersion = "0.15.0" // x-release-please-version
diff --git a/packages/sdk/js/src/gen/client/client.gen.ts b/packages/sdk/js/src/gen/client/client.gen.ts
index 34a8d0bec..aab8586ee 100644
--- a/packages/sdk/js/src/gen/client/client.gen.ts
+++ b/packages/sdk/js/src/gen/client/client.gen.ts
@@ -1,6 +1,8 @@
// This file is auto-generated by @hey-api/openapi-ts
import { createSseClient } from "../core/serverSentEvents.gen.js"
+import type { HttpMethod } from "../core/types.gen.js"
+import { getValidRequestBody } from "../core/utils.gen.js"
import type { Client, Config, RequestOptions, ResolvedRequestOptions } from "./types.gen.js"
import {
buildUrl,
@@ -49,12 +51,12 @@ export const createClient = (config: Config = {}): Client => {
await opts.requestValidator(opts)
}
- if (opts.body && opts.bodySerializer) {
+ if (opts.body !== undefined && opts.bodySerializer) {
opts.serializedBody = opts.bodySerializer(opts.body)
}
// remove Content-Type header if body is empty to avoid sending invalid requests
- if (opts.serializedBody === undefined || opts.serializedBody === "") {
+ if (opts.body === undefined || opts.serializedBody === "") {
opts.headers.delete("Content-Type")
}
@@ -69,7 +71,7 @@ export const createClient = (config: Config = {}): Client => {
const requestInit: ReqInit = {
redirect: "follow",
...opts,
- body: opts.serializedBody,
+ body: getValidRequestBody(opts),
}
let request = new Request(url, requestInit)
@@ -97,18 +99,36 @@ export const createClient = (config: Config = {}): Client => {
}
if (response.ok) {
+ const parseAs =
+ (opts.parseAs === "auto" ? getParseAs(response.headers.get("Content-Type")) : opts.parseAs) ?? "json"
+
if (response.status === 204 || response.headers.get("Content-Length") === "0") {
+ let emptyData: any
+ switch (parseAs) {
+ case "arrayBuffer":
+ case "blob":
+ case "text":
+ emptyData = await response[parseAs]()
+ break
+ case "formData":
+ emptyData = new FormData()
+ break
+ case "stream":
+ emptyData = response.body
+ break
+ case "json":
+ default:
+ emptyData = {}
+ break
+ }
return opts.responseStyle === "data"
- ? {}
+ ? emptyData
: {
- data: {},
+ data: emptyData,
...result,
}
}
- const parseAs =
- (opts.parseAs === "auto" ? getParseAs(response.headers.get("Content-Type")) : opts.parseAs) ?? "json"
-
let data: any
switch (parseAs) {
case "arrayBuffer":
@@ -178,35 +198,53 @@ export const createClient = (config: Config = {}): Client => {
}
}
- const makeMethod = (method: Required<Config>["method"]) => {
- const fn = (options: RequestOptions) => request({ ...options, method })
- fn.sse = async (options: RequestOptions) => {
- const { opts, url } = await beforeRequest(options)
- return createSseClient({
- ...opts,
- body: opts.body as BodyInit | null | undefined,
- headers: opts.headers as unknown as Record<string, string>,
- method,
- url,
- })
- }
- return fn
+ const makeMethodFn = (method: Uppercase<HttpMethod>) => (options: RequestOptions) => request({ ...options, method })
+
+ const makeSseFn = (method: Uppercase<HttpMethod>) => async (options: RequestOptions) => {
+ const { opts, url } = await beforeRequest(options)
+ return createSseClient({
+ ...opts,
+ body: opts.body as BodyInit | null | undefined,
+ headers: opts.headers as unknown as Record<string, string>,
+ method,
+ onRequest: async (url, init) => {
+ let request = new Request(url, init)
+ for (const fn of interceptors.request._fns) {
+ if (fn) {
+ request = await fn(request, opts)
+ }
+ }
+ return request
+ },
+ url,
+ })
}
return {
buildUrl,
- connect: makeMethod("CONNECT"),
- delete: makeMethod("DELETE"),
- get: makeMethod("GET"),
+ connect: makeMethodFn("CONNECT"),
+ delete: makeMethodFn("DELETE"),
+ get: makeMethodFn("GET"),
getConfig,
- head: makeMethod("HEAD"),
+ head: makeMethodFn("HEAD"),
interceptors,
- options: makeMethod("OPTIONS"),
- patch: makeMethod("PATCH"),
- post: makeMethod("POST"),
- put: makeMethod("PUT"),
+ options: makeMethodFn("OPTIONS"),
+ patch: makeMethodFn("PATCH"),
+ post: makeMethodFn("POST"),
+ put: makeMethodFn("PUT"),
request,
setConfig,
- trace: makeMethod("TRACE"),
+ sse: {
+ connect: makeSseFn("CONNECT"),
+ delete: makeSseFn("DELETE"),
+ get: makeSseFn("GET"),
+ head: makeSseFn("HEAD"),
+ options: makeSseFn("OPTIONS"),
+ patch: makeSseFn("PATCH"),
+ post: makeSseFn("POST"),
+ put: makeSseFn("PUT"),
+ trace: makeSseFn("TRACE"),
+ },
+ trace: makeMethodFn("TRACE"),
} as Client
}
diff --git a/packages/sdk/js/src/gen/client/types.gen.ts b/packages/sdk/js/src/gen/client/types.gen.ts
index db8e544cf..f16d2cd57 100644
--- a/packages/sdk/js/src/gen/client/types.gen.ts
+++ b/packages/sdk/js/src/gen/client/types.gen.ts
@@ -20,7 +20,7 @@ export interface Config<T extends ClientOptions = ClientOptions>
*
* @default globalThis.fetch
*/
- fetch?: (request: Request) => ReturnType<typeof fetch>
+ fetch?: typeof fetch
/**
* Please don't use the Fetch client for Next.js applications. The `next`
* options won't have any effect.
@@ -128,7 +128,7 @@ export interface ClientOptions {
throwOnError?: boolean
}
-type MethodFnBase = <
+type MethodFn = <
TData = unknown,
TError = unknown,
ThrowOnError extends boolean = false,
@@ -137,7 +137,7 @@ type MethodFnBase = <
options: Omit<RequestOptions<TData, TResponseStyle, ThrowOnError>, "method">,
) => RequestResult<TData, TError, ThrowOnError, TResponseStyle>
-type MethodFnServerSentEvents = <
+type SseFn = <
TData = unknown,
TError = unknown,
ThrowOnError extends boolean = false,
@@ -146,10 +146,6 @@ type MethodFnServerSentEvents = <
options: Omit<RequestOptions<TData, TResponseStyle, ThrowOnError>, "method">,
) => Promise<ServerSentEventsResult<TData, TError>>
-type MethodFn = MethodFnBase & {
- sse: MethodFnServerSentEvents
-}
-
type RequestFn = <
TData = unknown,
TError = unknown,
@@ -171,7 +167,7 @@ type BuildUrlFn = <
options: Pick<TData, "url"> & Options<TData>,
) => string
-export type Client = CoreClient<RequestFn, Config, MethodFn, BuildUrlFn> & {
+export type Client = CoreClient<RequestFn, Config, MethodFn, BuildUrlFn, SseFn> & {
interceptors: Middleware<Request, Response, unknown, ResolvedRequestOptions>
}
diff --git a/packages/sdk/js/src/gen/client/utils.gen.ts b/packages/sdk/js/src/gen/client/utils.gen.ts
index 209bfbe8e..71d52f776 100644
--- a/packages/sdk/js/src/gen/client/utils.gen.ts
+++ b/packages/sdk/js/src/gen/client/utils.gen.ts
@@ -162,14 +162,22 @@ export const mergeConfigs = (a: Config, b: Config): Config => {
return config
}
+const headersEntries = (headers: Headers): Array<[string, string]> => {
+ const entries: Array<[string, string]> = []
+ headers.forEach((value, key) => {
+ entries.push([key, value])
+ })
+ return entries
+}
+
export const mergeHeaders = (...headers: Array<Required<Config>["headers"] | undefined>): Headers => {
const mergedHeaders = new Headers()
for (const header of headers) {
- if (!header || typeof header !== "object") {
+ if (!header) {
continue
}
- const iterator = header instanceof Headers ? header.entries() : Object.entries(header)
+ const iterator = header instanceof Headers ? headersEntries(header) : Object.entries(header)
for (const [key, value] of iterator) {
if (value === null) {
diff --git a/packages/sdk/js/src/gen/core/serverSentEvents.gen.ts b/packages/sdk/js/src/gen/core/serverSentEvents.gen.ts
index 8f7fac549..09ef3fb39 100644
--- a/packages/sdk/js/src/gen/core/serverSentEvents.gen.ts
+++ b/packages/sdk/js/src/gen/core/serverSentEvents.gen.ts
@@ -5,6 +5,17 @@ import type { Config } from "./types.gen.js"
export type ServerSentEventsOptions<TData = unknown> = Omit<RequestInit, "method"> &
Pick<Config, "method" | "responseTransformer" | "responseValidator"> & {
/**
+ * Fetch API implementation. You can use this option to provide a custom
+ * fetch instance.
+ *
+ * @default globalThis.fetch
+ */
+ fetch?: typeof fetch
+ /**
+ * Implementing clients can call request interceptors inside this hook.
+ */
+ onRequest?: (url: string, init: RequestInit) => Promise<Request>
+ /**
* Callback invoked when a network or parsing error occurs during streaming.
*
* This option applies only if the endpoint returns a stream of events.
@@ -21,6 +32,7 @@ export type ServerSentEventsOptions<TData = unknown> = Omit<RequestInit, "method
* @returns Nothing (void).
*/
onSseEvent?: (event: StreamEvent<TData>) => void
+ serializedBody?: RequestInit["body"]
/**
* Default retry delay in milliseconds.
*
@@ -64,6 +76,7 @@ export type ServerSentEventsResult<TData = unknown, TReturn = void, TNext = unkn
}
export const createSseClient = <TData = unknown>({
+ onRequest,
onSseError,
onSseEvent,
responseTransformer,
@@ -99,7 +112,21 @@ export const createSseClient = <TData = unknown>({
}
try {
- const response = await fetch(url, { ...options, headers, signal })
+ const requestInit: RequestInit = {
+ redirect: "follow",
+ ...options,
+ body: options.serializedBody,
+ headers,
+ signal,
+ }
+ let request = new Request(url, requestInit)
+ if (onRequest) {
+ request = await onRequest(url, requestInit)
+ }
+ // fetch must be assigned here, otherwise it would throw the error:
+ // TypeError: Failed to execute 'fetch' on 'Window': Illegal invocation
+ const _fetch = options.fetch ?? globalThis.fetch
+ const response = await _fetch(request)
if (!response.ok) throw new Error(`SSE failed: ${response.status} ${response.statusText}`)
diff --git a/packages/sdk/js/src/gen/core/types.gen.ts b/packages/sdk/js/src/gen/core/types.gen.ts
index 16408b2d0..bfa77b8ac 100644
--- a/packages/sdk/js/src/gen/core/types.gen.ts
+++ b/packages/sdk/js/src/gen/core/types.gen.ts
@@ -3,24 +3,19 @@
import type { Auth, AuthToken } from "./auth.gen.js"
import type { BodySerializer, QuerySerializer, QuerySerializerOptions } from "./bodySerializer.gen.js"
-export interface Client<RequestFn = never, Config = unknown, MethodFn = never, BuildUrlFn = never> {
+export type HttpMethod = "connect" | "delete" | "get" | "head" | "options" | "patch" | "post" | "put" | "trace"
+
+export type Client<RequestFn = never, Config = unknown, MethodFn = never, BuildUrlFn = never, SseFn = never> = {
/**
* Returns the final request URL.
*/
buildUrl: BuildUrlFn
- connect: MethodFn
- delete: MethodFn
- get: MethodFn
getConfig: () => Config
- head: MethodFn
- options: MethodFn
- patch: MethodFn
- post: MethodFn
- put: MethodFn
request: RequestFn
setConfig: (config: Config) => Config
- trace: MethodFn
-}
+} & {
+ [K in HttpMethod]: MethodFn
+} & ([SseFn] extends [never] ? { sse?: never } : { sse: { [K in HttpMethod]: SseFn } })
export interface Config {
/**
@@ -47,7 +42,7 @@ export interface Config {
*
* {@link https://developer.mozilla.org/docs/Web/API/fetch#method See more}
*/
- method?: "CONNECT" | "DELETE" | "GET" | "HEAD" | "OPTIONS" | "PATCH" | "POST" | "PUT" | "TRACE"
+ method?: Uppercase<HttpMethod>
/**
* A function for serializing request query parameters. By default, arrays
* will be exploded in form style, objects will be exploded in deepObject
diff --git a/packages/sdk/js/src/gen/core/utils.gen.ts b/packages/sdk/js/src/gen/core/utils.gen.ts
index be18c608a..8a45f7269 100644
--- a/packages/sdk/js/src/gen/core/utils.gen.ts
+++ b/packages/sdk/js/src/gen/core/utils.gen.ts
@@ -1,6 +1,6 @@
// This file is auto-generated by @hey-api/openapi-ts
-import type { QuerySerializer } from "./bodySerializer.gen.js"
+import type { BodySerializer, QuerySerializer } from "./bodySerializer.gen.js"
import {
type ArraySeparatorStyle,
serializeArrayParam,
@@ -107,3 +107,31 @@ export const getUrl = ({
}
return url
}
+
+export function getValidRequestBody(options: {
+ body?: unknown
+ bodySerializer?: BodySerializer | null
+ serializedBody?: unknown
+}) {
+ const hasBody = options.body !== undefined
+ const isSerializedBody = hasBody && options.bodySerializer
+
+ if (isSerializedBody) {
+ if ("serializedBody" in options) {
+ const hasSerializedBody = options.serializedBody !== undefined && options.serializedBody !== ""
+
+ return hasSerializedBody ? options.serializedBody : null
+ }
+
+ // not all clients implement a serializedBody property (i.e. client-axios)
+ return options.body !== "" ? options.body : null
+ }
+
+ // plain/text body
+ if (hasBody) {
+ return options.body
+ }
+
+ // no body was provided
+ return undefined
+}
diff --git a/packages/sdk/js/src/gen/sdk.gen.ts b/packages/sdk/js/src/gen/sdk.gen.ts
index 7e0f0dc8b..f179afc12 100644
--- a/packages/sdk/js/src/gen/sdk.gen.ts
+++ b/packages/sdk/js/src/gen/sdk.gen.ts
@@ -6,8 +6,6 @@ import type {
ProjectListResponses,
ProjectCurrentData,
ProjectCurrentResponses,
- EventSubscribeData,
- EventSubscribeResponses,
ConfigGetData,
ConfigGetResponses,
ToolRegisterData,
@@ -101,6 +99,8 @@ import type {
AuthSetData,
AuthSetResponses,
AuthSetErrors,
+ EventSubscribeData,
+ EventSubscribeResponses,
} from "./types.gen.js"
import { client as _heyApiClient } from "./client.gen.js"
@@ -153,18 +153,6 @@ class Project extends _HeyApiClient {
}
}
-class Event extends _HeyApiClient {
- /**
- * Get events
- */
- public subscribe<ThrowOnError extends boolean = false>(options?: Options<EventSubscribeData, ThrowOnError>) {
- return (options?.client ?? this._client).get.sse<EventSubscribeResponses, unknown, ThrowOnError>({
- url: "/event",
- ...options,
- })
- }
-}
-
class Config extends _HeyApiClient {
/**
* Get config info
@@ -671,6 +659,18 @@ class Auth extends _HeyApiClient {
}
}
+class Event extends _HeyApiClient {
+ /**
+ * Get events
+ */
+ public subscribe<ThrowOnError extends boolean = false>(options?: Options<EventSubscribeData, ThrowOnError>) {
+ return (options?.client ?? this._client).sse.get<EventSubscribeResponses, unknown, ThrowOnError>({
+ url: "/event",
+ ...options,
+ })
+ }
+}
+
export class OpencodeClient extends _HeyApiClient {
/**
* Respond to a permission request
@@ -688,7 +688,6 @@ export class OpencodeClient extends _HeyApiClient {
})
}
project = new Project({ client: this._client })
- event = new Event({ client: this._client })
config = new Config({ client: this._client })
tool = new Tool({ client: this._client })
path = new Path({ client: this._client })
@@ -699,4 +698,5 @@ export class OpencodeClient extends _HeyApiClient {
app = new App({ client: this._client })
tui = new Tui({ client: this._client })
auth = new Auth({ client: this._client })
+ event = new Event({ client: this._client })
}
diff --git a/packages/sdk/js/src/gen/types.gen.ts b/packages/sdk/js/src/gen/types.gen.ts
index 9e268e3bd..e0cf7cdfd 100644
--- a/packages/sdk/js/src/gen/types.gen.ts
+++ b/packages/sdk/js/src/gen/types.gen.ts
@@ -10,440 +10,6 @@ export type Project = {
}
}
-export type EventInstallationUpdated = {
- type: "installation.updated"
- properties: {
- version: string
- }
-}
-
-export type EventLspClientDiagnostics = {
- type: "lsp.client.diagnostics"
- properties: {
- serverID: string
- path: string
- }
-}
-
-export type UserMessage = {
- id: string
- sessionID: string
- role: "user"
- time: {
- created: number
- }
-}
-
-export type ProviderAuthError = {
- name: "ProviderAuthError"
- data: {
- providerID: string
- message: string
- }
-}
-
-export type UnknownError = {
- name: "UnknownError"
- data: {
- message: string
- }
-}
-
-export type MessageOutputLengthError = {
- name: "MessageOutputLengthError"
- data: {
- [key: string]: unknown
- }
-}
-
-export type MessageAbortedError = {
- name: "MessageAbortedError"
- data: {
- message: string
- }
-}
-
-export type AssistantMessage = {
- id: string
- sessionID: string
- role: "assistant"
- time: {
- created: number
- completed?: number
- }
- error?: ProviderAuthError | UnknownError | MessageOutputLengthError | MessageAbortedError
- system: Array<string>
- modelID: string
- providerID: string
- mode: string
- path: {
- cwd: string
- root: string
- }
- summary?: boolean
- cost: number
- tokens: {
- input: number
- output: number
- reasoning: number
- cache: {
- read: number
- write: number
- }
- }
-}
-
-export type Message = UserMessage | AssistantMessage
-
-export type EventMessageUpdated = {
- type: "message.updated"
- properties: {
- info: Message
- }
-}
-
-export type EventMessageRemoved = {
- type: "message.removed"
- properties: {
- sessionID: string
- messageID: string
- }
-}
-
-export type TextPart = {
- id: string
- sessionID: string
- messageID: string
- type: "text"
- text: string
- synthetic?: boolean
- time?: {
- start: number
- end?: number
- }
-}
-
-export type ReasoningPart = {
- id: string
- sessionID: string
- messageID: string
- type: "reasoning"
- text: string
- metadata?: {
- [key: string]: unknown
- }
- time: {
- start: number
- end?: number
- }
-}
-
-export type FilePartSourceText = {
- value: string
- start: number
- end: number
-}
-
-export type FileSource = {
- text: FilePartSourceText
- type: "file"
- path: string
-}
-
-export type Range = {
- start: {
- line: number
- character: number
- }
- end: {
- line: number
- character: number
- }
-}
-
-export type SymbolSource = {
- text: FilePartSourceText
- type: "symbol"
- path: string
- range: Range
- name: string
- kind: number
-}
-
-export type FilePartSource = FileSource | SymbolSource
-
-export type FilePart = {
- id: string
- sessionID: string
- messageID: string
- type: "file"
- mime: string
- filename?: string
- url: string
- source?: FilePartSource
-}
-
-export type ToolStatePending = {
- status: "pending"
-}
-
-export type ToolStateRunning = {
- status: "running"
- input: unknown
- title?: string
- metadata?: {
- [key: string]: unknown
- }
- time: {
- start: number
- }
-}
-
-export type ToolStateCompleted = {
- status: "completed"
- input: {
- [key: string]: unknown
- }
- output: string
- title: string
- metadata: {
- [key: string]: unknown
- }
- time: {
- start: number
- end: number
- compacted?: number
- }
-}
-
-export type ToolStateError = {
- status: "error"
- input: {
- [key: string]: unknown
- }
- error: string
- metadata?: {
- [key: string]: unknown
- }
- time: {
- start: number
- end: number
- }
-}
-
-export type ToolState = ToolStatePending | ToolStateRunning | ToolStateCompleted | ToolStateError
-
-export type ToolPart = {
- id: string
- sessionID: string
- messageID: string
- type: "tool"
- callID: string
- tool: string
- state: ToolState
-}
-
-export type StepStartPart = {
- id: string
- sessionID: string
- messageID: string
- type: "step-start"
-}
-
-export type StepFinishPart = {
- id: string
- sessionID: string
- messageID: string
- type: "step-finish"
- cost: number
- tokens: {
- input: number
- output: number
- reasoning: number
- cache: {
- read: number
- write: number
- }
- }
-}
-
-export type SnapshotPart = {
- id: string
- sessionID: string
- messageID: string
- type: "snapshot"
- snapshot: string
-}
-
-export type PatchPart = {
- id: string
- sessionID: string
- messageID: string
- type: "patch"
- hash: string
- files: Array<string>
-}
-
-export type AgentPart = {
- id: string
- sessionID: string
- messageID: string
- type: "agent"
- name: string
- source?: {
- value: string
- start: number
- end: number
- }
-}
-
-export type Part =
- | TextPart
- | ReasoningPart
- | FilePart
- | ToolPart
- | StepStartPart
- | StepFinishPart
- | SnapshotPart
- | PatchPart
- | AgentPart
-
-export type EventMessagePartUpdated = {
- type: "message.part.updated"
- properties: {
- part: Part
- }
-}
-
-export type EventMessagePartRemoved = {
- type: "message.part.removed"
- properties: {
- sessionID: string
- messageID: string
- partID: string
- }
-}
-
-export type EventSessionCompacted = {
- type: "session.compacted"
- properties: {
- sessionID: string
- }
-}
-
-export type Permission = {
- id: string
- type: string
- pattern?: string | Array<string>
- sessionID: string
- messageID: string
- callID?: string
- title: string
- metadata: {
- [key: string]: unknown
- }
- time: {
- created: number
- }
-}
-
-export type EventPermissionUpdated = {
- type: "permission.updated"
- properties: Permission
-}
-
-export type EventPermissionReplied = {
- type: "permission.replied"
- properties: {
- sessionID: string
- permissionID: string
- response: string
- }
-}
-
-export type EventFileEdited = {
- type: "file.edited"
- properties: {
- file: string
- }
-}
-
-export type EventSessionIdle = {
- type: "session.idle"
- properties: {
- sessionID: string
- }
-}
-
-export type Session = {
- id: string
- projectID: string
- directory: string
- parentID?: string
- share?: {
- url: string
- }
- title: string
- version: string
- time: {
- created: number
- updated: number
- compacting?: number
- }
- revert?: {
- messageID: string
- partID?: string
- snapshot?: string
- diff?: string
- }
-}
-
-export type EventSessionUpdated = {
- type: "session.updated"
- properties: {
- info: Session
- }
-}
-
-export type EventSessionDeleted = {
- type: "session.deleted"
- properties: {
- info: Session
- }
-}
-
-export type EventSessionError = {
- type: "session.error"
- properties: {
- sessionID?: string
- error?: ProviderAuthError | UnknownError | MessageOutputLengthError | MessageAbortedError
- }
-}
-
-export type EventServerConnected = {
- type: "server.connected"
- properties: {
- [key: string]: unknown
- }
-}
-
-export type Event =
- | EventInstallationUpdated
- | EventLspClientDiagnostics
- | EventMessageUpdated
- | EventMessageRemoved
- | EventMessagePartUpdated
- | EventMessagePartRemoved
- | EventSessionCompacted
- | EventPermissionUpdated
- | EventPermissionReplied
- | EventFileEdited
- | EventSessionIdle
- | EventSessionUpdated
- | EventSessionDeleted
- | EventSessionError
- | EventServerConnected
-
/**
* Custom keybind configurations
*/
@@ -983,6 +549,297 @@ export type Path = {
directory: string
}
+export type Session = {
+ id: string
+ projectID: string
+ directory: string
+ parentID?: string
+ share?: {
+ url: string
+ }
+ title: string
+ version: string
+ time: {
+ created: number
+ updated: number
+ compacting?: number
+ }
+ revert?: {
+ messageID: string
+ partID?: string
+ snapshot?: string
+ diff?: string
+ }
+}
+
+export type UserMessage = {
+ id: string
+ sessionID: string
+ role: "user"
+ time: {
+ created: number
+ }
+}
+
+export type ProviderAuthError = {
+ name: "ProviderAuthError"
+ data: {
+ providerID: string
+ message: string
+ }
+}
+
+export type UnknownError = {
+ name: "UnknownError"
+ data: {
+ message: string
+ }
+}
+
+export type MessageOutputLengthError = {
+ name: "MessageOutputLengthError"
+ data: {
+ [key: string]: unknown
+ }
+}
+
+export type MessageAbortedError = {
+ name: "MessageAbortedError"
+ data: {
+ message: string
+ }
+}
+
+export type AssistantMessage = {
+ id: string
+ sessionID: string
+ role: "assistant"
+ time: {
+ created: number
+ completed?: number
+ }
+ error?: ProviderAuthError | UnknownError | MessageOutputLengthError | MessageAbortedError
+ system: Array<string>
+ modelID: string
+ providerID: string
+ mode: string
+ path: {
+ cwd: string
+ root: string
+ }
+ summary?: boolean
+ cost: number
+ tokens: {
+ input: number
+ output: number
+ reasoning: number
+ cache: {
+ read: number
+ write: number
+ }
+ }
+}
+
+export type Message = UserMessage | AssistantMessage
+
+export type TextPart = {
+ id: string
+ sessionID: string
+ messageID: string
+ type: "text"
+ text: string
+ synthetic?: boolean
+ time?: {
+ start: number
+ end?: number
+ }
+}
+
+export type ReasoningPart = {
+ id: string
+ sessionID: string
+ messageID: string
+ type: "reasoning"
+ text: string
+ metadata?: {
+ [key: string]: unknown
+ }
+ time: {
+ start: number
+ end?: number
+ }
+}
+
+export type FilePartSourceText = {
+ value: string
+ start: number
+ end: number
+}
+
+export type FileSource = {
+ text: FilePartSourceText
+ type: "file"
+ path: string
+}
+
+export type Range = {
+ start: {
+ line: number
+ character: number
+ }
+ end: {
+ line: number
+ character: number
+ }
+}
+
+export type SymbolSource = {
+ text: FilePartSourceText
+ type: "symbol"
+ path: string
+ range: Range
+ name: string
+ kind: number
+}
+
+export type FilePartSource = FileSource | SymbolSource
+
+export type FilePart = {
+ id: string
+ sessionID: string
+ messageID: string
+ type: "file"
+ mime: string
+ filename?: string
+ url: string
+ source?: FilePartSource
+}
+
+export type ToolStatePending = {
+ status: "pending"
+}
+
+export type ToolStateRunning = {
+ status: "running"
+ input: unknown
+ title?: string
+ metadata?: {
+ [key: string]: unknown
+ }
+ time: {
+ start: number
+ }
+}
+
+export type ToolStateCompleted = {
+ status: "completed"
+ input: {
+ [key: string]: unknown
+ }
+ output: string
+ title: string
+ metadata: {
+ [key: string]: unknown
+ }
+ time: {
+ start: number
+ end: number
+ compacted?: number
+ }
+}
+
+export type ToolStateError = {
+ status: "error"
+ input: {
+ [key: string]: unknown
+ }
+ error: string
+ metadata?: {
+ [key: string]: unknown
+ }
+ time: {
+ start: number
+ end: number
+ }
+}
+
+export type ToolState = ToolStatePending | ToolStateRunning | ToolStateCompleted | ToolStateError
+
+export type ToolPart = {
+ id: string
+ sessionID: string
+ messageID: string
+ type: "tool"
+ callID: string
+ tool: string
+ state: ToolState
+}
+
+export type StepStartPart = {
+ id: string
+ sessionID: string
+ messageID: string
+ type: "step-start"
+}
+
+export type StepFinishPart = {
+ id: string
+ sessionID: string
+ messageID: string
+ type: "step-finish"
+ cost: number
+ tokens: {
+ input: number
+ output: number
+ reasoning: number
+ cache: {
+ read: number
+ write: number
+ }
+ }
+}
+
+export type SnapshotPart = {
+ id: string
+ sessionID: string
+ messageID: string
+ type: "snapshot"
+ snapshot: string
+}
+
+export type PatchPart = {
+ id: string
+ sessionID: string
+ messageID: string
+ type: "patch"
+ hash: string
+ files: Array<string>
+}
+
+export type AgentPart = {
+ id: string
+ sessionID: string
+ messageID: string
+ type: "agent"
+ name: string
+ source?: {
+ value: string
+ start: number
+ end: number
+ }
+}
+
+export type Part =
+ | TextPart
+ | ReasoningPart
+ | FilePart
+ | ToolPart
+ | StepStartPart
+ | StepFinishPart
+ | SnapshotPart
+ | PatchPart
+ | AgentPart
+
export type TextPartInput = {
id?: string
type: "text"
@@ -1151,6 +1008,166 @@ export type WellKnownAuth = {
export type Auth = OAuth | ApiAuth | WellKnownAuth
+export type EventInstallationUpdated = {
+ type: "installation.updated"
+ properties: {
+ version: string
+ }
+}
+
+export type EventLspClientDiagnostics = {
+ type: "lsp.client.diagnostics"
+ properties: {
+ serverID: string
+ path: string
+ }
+}
+
+export type EventMessageUpdated = {
+ type: "message.updated"
+ properties: {
+ info: Message
+ }
+}
+
+export type EventMessageRemoved = {
+ type: "message.removed"
+ properties: {
+ sessionID: string
+ messageID: string
+ }
+}
+
+export type EventMessagePartUpdated = {
+ type: "message.part.updated"
+ properties: {
+ part: Part
+ }
+}
+
+export type EventMessagePartRemoved = {
+ type: "message.part.removed"
+ properties: {
+ sessionID: string
+ messageID: string
+ partID: string
+ }
+}
+
+export type EventSessionCompacted = {
+ type: "session.compacted"
+ properties: {
+ sessionID: string
+ }
+}
+
+export type Permission = {
+ id: string
+ type: string
+ pattern?: string | Array<string>
+ sessionID: string
+ messageID: string
+ callID?: string
+ title: string
+ metadata: {
+ [key: string]: unknown
+ }
+ time: {
+ created: number
+ }
+}
+
+export type EventPermissionUpdated = {
+ type: "permission.updated"
+ properties: Permission
+}
+
+export type EventPermissionReplied = {
+ type: "permission.replied"
+ properties: {
+ sessionID: string
+ permissionID: string
+ response: string
+ }
+}
+
+export type EventFileEdited = {
+ type: "file.edited"
+ properties: {
+ file: string
+ }
+}
+
+export type EventSessionIdle = {
+ type: "session.idle"
+ properties: {
+ sessionID: string
+ }
+}
+
+export type EventSessionUpdated = {
+ type: "session.updated"
+ properties: {
+ info: Session
+ }
+}
+
+export type EventSessionDeleted = {
+ type: "session.deleted"
+ properties: {
+ info: Session
+ }
+}
+
+export type EventSessionError = {
+ type: "session.error"
+ properties: {
+ sessionID?: string
+ error?: ProviderAuthError | UnknownError | MessageOutputLengthError | MessageAbortedError
+ }
+}
+
+export type EventServerConnected = {
+ type: "server.connected"
+ properties: {
+ [key: string]: unknown
+ }
+}
+
+export type EventFileWatcherUpdated = {
+ type: "file.watcher.updated"
+ properties: {
+ file: string
+ event: "add" | "change" | "unlink"
+ }
+}
+
+export type EventIdeInstalled = {
+ type: "ide.installed"
+ properties: {
+ ide: string
+ }
+}
+
+export type Event =
+ | EventInstallationUpdated
+ | EventLspClientDiagnostics
+ | EventMessageUpdated
+ | EventMessageRemoved
+ | EventMessagePartUpdated
+ | EventMessagePartRemoved
+ | EventSessionCompacted
+ | EventPermissionUpdated
+ | EventPermissionReplied
+ | EventFileEdited
+ | EventSessionIdle
+ | EventSessionUpdated
+ | EventSessionDeleted
+ | EventSessionError
+ | EventServerConnected
+ | EventFileWatcherUpdated
+ | EventIdeInstalled
+
export type ProjectListData = {
body?: never
path?: never
@@ -1187,24 +1204,6 @@ export type ProjectCurrentResponses = {
export type ProjectCurrentResponse = ProjectCurrentResponses[keyof ProjectCurrentResponses]
-export type EventSubscribeData = {
- body?: never
- path?: never
- query?: {
- directory?: string
- }
- url: "/event"
-}
-
-export type EventSubscribeResponses = {
- /**
- * Event stream
- */
- 200: Event
-}
-
-export type EventSubscribeResponse = EventSubscribeResponses[keyof EventSubscribeResponses]
-
export type ConfigGetData = {
body?: never
path?: never
@@ -2210,6 +2209,24 @@ export type AuthSetResponses = {
export type AuthSetResponse = AuthSetResponses[keyof AuthSetResponses]
+export type EventSubscribeData = {
+ body?: never
+ path?: never
+ query?: {
+ directory?: string
+ }
+ url: "/event"
+}
+
+export type EventSubscribeResponses = {
+ /**
+ * Event stream
+ */
+ 200: Event
+}
+
+export type EventSubscribeResponse = EventSubscribeResponses[keyof EventSubscribeResponses]
+
export type ClientOptions = {
baseUrl: `${string}://${string}` | (string & {})
}