Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
dbba4a97aa | ||
|
|
0dc586faef | ||
|
|
f19c6b05f2 | ||
|
|
bc34f08333 | ||
|
|
b7ee16aabd | ||
|
|
ed1b0d97bf | ||
|
|
8d3b2fb821 | ||
|
|
fa991920bc | ||
|
|
5e79e3d7a5 | ||
|
|
966015c9ae | ||
|
|
61f057337a | ||
|
|
0b261054a2 | ||
|
|
e2e481cbb5 | ||
|
|
5140e83012 |
@@ -458,7 +458,7 @@
|
||||
|
||||
"@types/babel__traverse": ["@types/babel__traverse@7.20.7", "", { "dependencies": { "@babel/types": "^7.20.7" } }, "sha512-dkO5fhS7+/oos4ciWxyEyjWe48zmG6wbCheo/G2ZnHx4fs3EU6YC6UM8rk56gAjNJ9P3MTH2jo5jb92/K6wbng=="],
|
||||
|
||||
"@types/bun": ["@types/bun@1.2.16", "", { "dependencies": { "bun-types": "1.2.16" } }, "sha512-1aCZJ/6nSiViw339RsaNhkNoEloLaPzZhxMOYEa7OzRzO41IGg5n/7I43/ZIAW/c+Q6cT12Vf7fOZOoVIzb5BQ=="],
|
||||
"@types/bun": ["@types/bun@1.2.17", "", { "dependencies": { "bun-types": "1.2.17" } }, "sha512-l/BYs/JYt+cXA/0+wUhulYJB6a6p//GTPiJ7nV+QHa8iiId4HZmnu/3J/SowP5g0rTiERY2kfGKXEK5Ehltx4Q=="],
|
||||
|
||||
"@types/debug": ["@types/debug@4.1.12", "", { "dependencies": { "@types/ms": "*" } }, "sha512-vIChWdVG3LG1SMxEvI/AK+FWJthlrqlTu7fbrlywTkkaONwk/UAGaULXRlf8vkzFBLVm0zkMdCquhL5aOjhXPQ=="],
|
||||
|
||||
@@ -596,7 +596,7 @@
|
||||
|
||||
"buffer": ["buffer@4.9.2", "", { "dependencies": { "base64-js": "^1.0.2", "ieee754": "^1.1.4", "isarray": "^1.0.0" } }, "sha512-xq+q3SRMOxGivLhBNaUdC64hDTQwejJ+H0T/NB1XMtTVEwNTrfFF3gAxiyW0Bu/xWEGhjVKgUcMhCrUy2+uCWg=="],
|
||||
|
||||
"bun-types": ["bun-types@1.2.16", "", { "dependencies": { "@types/node": "*" } }, "sha512-ciXLrHV4PXax9vHvUrkvun9VPVGOVwbbbBF/Ev1cXz12lyEZMoJpIJABOfPcN9gDJRaiKF9MVbSygLg4NXu3/A=="],
|
||||
"bun-types": ["bun-types@1.2.17", "", { "dependencies": { "@types/node": "*" } }, "sha512-ElC7ItwT3SCQwYZDYoAH+q6KT4Fxjl8DtZ6qDulUFBmXA8YB4xo+l54J9ZJN+k2pphfn9vk7kfubeSd5QfTVJQ=="],
|
||||
|
||||
"bundle-name": ["bundle-name@4.1.0", "", { "dependencies": { "run-applescript": "^7.0.0" } }, "sha512-tjwM5exMg6BGRI+kNmTntNsvdZS1X8BFYS6tnJ2hdH0kVxM6/eVZ2xy+FqStSWvYmtfFMDLIxurorHwDKfDz5Q=="],
|
||||
|
||||
|
||||
+1
-7
@@ -1,9 +1,3 @@
|
||||
{
|
||||
"$schema": "https://opencode.ai/config.json",
|
||||
"mcp": {
|
||||
"sentry": {
|
||||
"type": "remote",
|
||||
"url": "https://mcp.sentry.dev/sse"
|
||||
}
|
||||
}
|
||||
"$schema": "https://opencode.ai/config.json"
|
||||
}
|
||||
|
||||
@@ -46,7 +46,7 @@ export namespace App {
|
||||
const data = path.join(
|
||||
Global.Path.data,
|
||||
"project",
|
||||
git ? git.split(path.sep).join("-") : "global",
|
||||
git ? git.split(path.sep).filter(Boolean).join("-") : "global",
|
||||
)
|
||||
const stateFile = Bun.file(path.join(data, APP_JSON))
|
||||
const state = (await stateFile.json().catch(() => ({}))) as {
|
||||
|
||||
@@ -37,7 +37,7 @@ export namespace AuthGithubCopilot {
|
||||
headers: {
|
||||
Accept: "application/json",
|
||||
"Content-Type": "application/json",
|
||||
"User-Agent": "GithubCopilot/1.155.0",
|
||||
"User-Agent": "GitHubCopilotChat/0.26.7",
|
||||
},
|
||||
body: JSON.stringify({
|
||||
client_id: CLIENT_ID,
|
||||
@@ -60,7 +60,7 @@ export namespace AuthGithubCopilot {
|
||||
headers: {
|
||||
Accept: "application/json",
|
||||
"Content-Type": "application/json",
|
||||
"User-Agent": "GithubCopilot/1.155.0",
|
||||
"User-Agent": "GitHubCopilotChat/0.26.7",
|
||||
},
|
||||
body: JSON.stringify({
|
||||
client_id: CLIENT_ID,
|
||||
@@ -101,9 +101,9 @@ export namespace AuthGithubCopilot {
|
||||
headers: {
|
||||
Accept: "application/json",
|
||||
Authorization: `Bearer ${info.refresh}`,
|
||||
"User-Agent": "GithubCopilot/1.155.0",
|
||||
"Editor-Version": "vscode/1.85.1",
|
||||
"Editor-Plugin-Version": "copilot/1.155.0",
|
||||
"User-Agent": "GitHubCopilotChat/0.26.7",
|
||||
"Editor-Version": "vscode/1.99.3",
|
||||
"Editor-Plugin-Version": "copilot-chat/0.26.7",
|
||||
},
|
||||
})
|
||||
|
||||
|
||||
@@ -53,9 +53,12 @@ export namespace BunProc {
|
||||
if (parsed.dependencies[pkg] === version) return mod
|
||||
parsed.dependencies[pkg] = version
|
||||
await Bun.write(pkgjson, JSON.stringify(parsed, null, 2))
|
||||
await BunProc.run(["install"], {
|
||||
cwd: Global.Path.cache,
|
||||
}).catch((e) => {
|
||||
await BunProc.run(
|
||||
["install", "--registry", "https://registry.npmjs.org/"],
|
||||
{
|
||||
cwd: Global.Path.cache,
|
||||
},
|
||||
).catch((e) => {
|
||||
new InstallFailedError(
|
||||
{ pkg, version },
|
||||
{
|
||||
|
||||
@@ -10,14 +10,14 @@ import { map, pipe, sortBy, values } from "remeda"
|
||||
|
||||
export const AuthCommand = cmd({
|
||||
command: "auth",
|
||||
describe: "Manage credentials",
|
||||
describe: "manage credentials",
|
||||
builder: (yargs) =>
|
||||
yargs
|
||||
.command(AuthLoginCommand)
|
||||
.command(AuthLogoutCommand)
|
||||
.command(AuthListCommand)
|
||||
.demandCommand(),
|
||||
async handler() {},
|
||||
async handler() { },
|
||||
})
|
||||
|
||||
export const AuthListCommand = cmd({
|
||||
@@ -41,7 +41,7 @@ export const AuthListCommand = cmd({
|
||||
|
||||
export const AuthLoginCommand = cmd({
|
||||
command: "login",
|
||||
describe: "login to a provider",
|
||||
describe: "log in to a provider",
|
||||
async handler() {
|
||||
UI.empty()
|
||||
prompts.intro("Add credential")
|
||||
@@ -195,7 +195,7 @@ export const AuthLoginCommand = cmd({
|
||||
|
||||
export const AuthLogoutCommand = cmd({
|
||||
command: "logout",
|
||||
describe: "logout from a configured provider",
|
||||
describe: "log out from a configured provider",
|
||||
async handler() {
|
||||
UI.empty()
|
||||
const credentials = await Auth.all().then((x) => Object.entries(x))
|
||||
|
||||
@@ -25,7 +25,7 @@ const TOOL: Record<string, [string, string]> = {
|
||||
|
||||
export const RunCommand = cmd({
|
||||
command: "run [message..]",
|
||||
describe: "Run opencode with a message",
|
||||
describe: "run opencode with a message",
|
||||
builder: (yargs: Argv) => {
|
||||
return yargs
|
||||
.positional("message", {
|
||||
@@ -36,12 +36,12 @@ export const RunCommand = cmd({
|
||||
})
|
||||
.option("continue", {
|
||||
alias: ["c"],
|
||||
describe: "Continue the last session",
|
||||
describe: "continue the last session",
|
||||
type: "boolean",
|
||||
})
|
||||
.option("session", {
|
||||
alias: ["s"],
|
||||
describe: "Session ID to continue",
|
||||
describe: "session id to continue",
|
||||
type: "string",
|
||||
})
|
||||
.option("share", {
|
||||
@@ -51,7 +51,7 @@ export const RunCommand = cmd({
|
||||
.option("model", {
|
||||
type: "string",
|
||||
alias: ["m"],
|
||||
describe: "Model to use in the format of provider/model",
|
||||
describe: "model to use in the format of provider/model",
|
||||
})
|
||||
},
|
||||
handler: async (args) => {
|
||||
|
||||
@@ -5,16 +5,16 @@ import { Installation } from "../../installation"
|
||||
|
||||
export const UpgradeCommand = {
|
||||
command: "upgrade [target]",
|
||||
describe: "upgrade opencode to the latest version or a specific version",
|
||||
describe: "upgrade opencode to the latest or a specific version",
|
||||
builder: (yargs: Argv) => {
|
||||
return yargs
|
||||
.positional("target", {
|
||||
describe: "specific version to upgrade to (e.g., '0.1.48' or 'v0.1.48')",
|
||||
describe: "version to upgrade to, for ex '0.1.48' or 'v0.1.48'",
|
||||
type: "string",
|
||||
})
|
||||
.option("method", {
|
||||
alias: "m",
|
||||
describe: "installation method to use (curl, npm, pnpm, bun, brew)",
|
||||
describe: "installation method to use",
|
||||
type: "string",
|
||||
choices: ["curl", "npm", "pnpm", "bun", "brew"],
|
||||
})
|
||||
|
||||
+5
-2
@@ -116,14 +116,17 @@ export namespace Ripgrep {
|
||||
export async function files(input: {
|
||||
cwd: string
|
||||
query?: string
|
||||
glob?: string
|
||||
limit?: number
|
||||
}) {
|
||||
const commands = [`${await filepath()} --files --hidden --glob='!.git/*'`]
|
||||
const commands = [
|
||||
`${await filepath()} --files --hidden --glob='!.git/*' ${input.glob ? `--glob='${input.glob}'` : ``}`,
|
||||
]
|
||||
if (input.query)
|
||||
commands.push(`${await Fzf.filepath()} --filter=${input.query}`)
|
||||
if (input.limit) commands.push(`head -n ${input.limit}`)
|
||||
const joined = commands.join(" | ")
|
||||
const result = await $`${{ raw: joined }}`.cwd(input.cwd).text()
|
||||
const result = await $`${{ raw: joined }}`.cwd(input.cwd).nothrow().text()
|
||||
return result.split("\n").filter(Boolean)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -20,15 +20,17 @@ import { Bus } from "./bus"
|
||||
import { Config } from "./config/config"
|
||||
import { NamedError } from "./util/error"
|
||||
import { FormatError } from "./cli/error"
|
||||
import { MCP } from "./mcp"
|
||||
|
||||
const cancel = new AbortController()
|
||||
|
||||
const cli = yargs(hideBin(process.argv))
|
||||
.scriptName("opencode")
|
||||
.version(Installation.VERSION)
|
||||
.help("help", "show help")
|
||||
.alias("help", "h")
|
||||
.version("version", "show version number", Installation.VERSION)
|
||||
.alias("version", "v")
|
||||
.option("print-logs", {
|
||||
describe: "Print logs to stderr",
|
||||
describe: "print logs to stderr",
|
||||
type: "boolean",
|
||||
})
|
||||
.middleware(async () => {
|
||||
@@ -41,7 +43,7 @@ const cli = yargs(hideBin(process.argv))
|
||||
.usage("\n" + UI.logo())
|
||||
.command({
|
||||
command: "$0 [project]",
|
||||
describe: "start opencode TUI",
|
||||
describe: "start opencode tui",
|
||||
builder: (yargs) =>
|
||||
yargs.positional("project", {
|
||||
type: "string",
|
||||
@@ -90,21 +92,21 @@ const cli = yargs(hideBin(process.argv))
|
||||
},
|
||||
})
|
||||
|
||||
;(async () => {
|
||||
if (Installation.VERSION === "dev") return
|
||||
if (Installation.isSnapshot()) return
|
||||
const config = await Config.global()
|
||||
if (config.autoupdate === false) return
|
||||
const latest = await Installation.latest()
|
||||
if (Installation.VERSION === latest) return
|
||||
const method = await Installation.method()
|
||||
if (method === "unknown") return
|
||||
await Installation.upgrade(method, latest)
|
||||
.then(() => {
|
||||
Bus.publish(Installation.Event.Updated, { version: latest })
|
||||
})
|
||||
.catch(() => {})
|
||||
})()
|
||||
; (async () => {
|
||||
if (Installation.VERSION === "dev") return
|
||||
if (Installation.isSnapshot()) return
|
||||
const config = await Config.global()
|
||||
if (config.autoupdate === false) return
|
||||
const latest = await Installation.latest()
|
||||
if (Installation.VERSION === latest) return
|
||||
const method = await Installation.method()
|
||||
if (method === "unknown") return
|
||||
await Installation.upgrade(method, latest)
|
||||
.then(() => {
|
||||
Bus.publish(Installation.Event.Updated, { version: latest })
|
||||
})
|
||||
.catch(() => { })
|
||||
})()
|
||||
|
||||
await proc.exited
|
||||
server.stop()
|
||||
|
||||
@@ -0,0 +1,4 @@
|
||||
export async function data() {
|
||||
const json = await fetch("https://models.dev/api.json").then((x) => x.text())
|
||||
return json
|
||||
}
|
||||
@@ -2,6 +2,7 @@ import { Global } from "../global"
|
||||
import { Log } from "../util/log"
|
||||
import path from "path"
|
||||
import { z } from "zod"
|
||||
import { data } from "./models-macro" with { type: "macro" }
|
||||
|
||||
export namespace ModelsDev {
|
||||
const log = Log.create({ service: "models.dev" })
|
||||
@@ -54,16 +55,15 @@ export namespace ModelsDev {
|
||||
refresh()
|
||||
return result as Record<string, Provider>
|
||||
}
|
||||
await refresh()
|
||||
return get()
|
||||
refresh()
|
||||
const json = await data()
|
||||
return JSON.parse(json) as Record<string, Provider>
|
||||
}
|
||||
|
||||
async function refresh() {
|
||||
const file = Bun.file(filepath)
|
||||
log.info("refreshing")
|
||||
const result = await fetch("https://models.dev/api.json")
|
||||
if (!result.ok)
|
||||
throw new Error(`Failed to fetch models.dev: ${result.statusText}`)
|
||||
await Bun.write(file, result)
|
||||
const result = await fetch("https://models.dev/api.json").catch(() => {})
|
||||
if (result && result.ok) await Bun.write(file, result)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -89,9 +89,11 @@ export namespace Provider {
|
||||
const headers = {
|
||||
...init.headers,
|
||||
Authorization: `Bearer ${token}`,
|
||||
"User-Agent": "GithubCopilot/1.155.0",
|
||||
"Editor-Version": "vscode/1.85.1",
|
||||
"Editor-Plugin-Version": "copilot/1.155.0",
|
||||
"User-Agent": "GitHubCopilotChat/0.26.7",
|
||||
"Editor-Version": "vscode/1.99.3",
|
||||
"Editor-Plugin-Version": "copilot-chat/0.26.7",
|
||||
"Copilot-Integration-Id": "vscode-chat",
|
||||
"Openai-Intent": "conversation-edits",
|
||||
}
|
||||
delete headers["x-api-key"]
|
||||
return fetch(input, {
|
||||
|
||||
@@ -135,53 +135,55 @@ export namespace Message {
|
||||
id: z.string(),
|
||||
role: z.enum(["user", "assistant"]),
|
||||
parts: z.array(Part),
|
||||
metadata: z.object({
|
||||
time: z.object({
|
||||
created: z.number(),
|
||||
completed: z.number().optional(),
|
||||
}),
|
||||
error: z
|
||||
.discriminatedUnion("name", [
|
||||
Provider.AuthError.Schema,
|
||||
NamedError.Unknown.Schema,
|
||||
])
|
||||
.optional(),
|
||||
sessionID: z.string(),
|
||||
tool: z.record(
|
||||
z.string(),
|
||||
z
|
||||
metadata: z
|
||||
.object({
|
||||
time: z.object({
|
||||
created: z.number(),
|
||||
completed: z.number().optional(),
|
||||
}),
|
||||
error: z
|
||||
.discriminatedUnion("name", [
|
||||
Provider.AuthError.Schema,
|
||||
NamedError.Unknown.Schema,
|
||||
])
|
||||
.optional(),
|
||||
sessionID: z.string(),
|
||||
tool: z.record(
|
||||
z.string(),
|
||||
z
|
||||
.object({
|
||||
title: z.string(),
|
||||
time: z.object({
|
||||
start: z.number(),
|
||||
end: z.number(),
|
||||
}),
|
||||
})
|
||||
.catchall(z.any()),
|
||||
),
|
||||
assistant: z
|
||||
.object({
|
||||
title: z.string(),
|
||||
time: z.object({
|
||||
start: z.number(),
|
||||
end: z.number(),
|
||||
system: z.string().array(),
|
||||
modelID: z.string(),
|
||||
providerID: z.string(),
|
||||
path: z.object({
|
||||
cwd: z.string(),
|
||||
root: z.string(),
|
||||
}),
|
||||
cost: z.number(),
|
||||
summary: z.boolean().optional(),
|
||||
tokens: z.object({
|
||||
input: z.number(),
|
||||
output: z.number(),
|
||||
reasoning: z.number(),
|
||||
cache: z.object({
|
||||
read: z.number(),
|
||||
write: z.number(),
|
||||
}),
|
||||
}),
|
||||
})
|
||||
.catchall(z.any()),
|
||||
),
|
||||
assistant: z
|
||||
.object({
|
||||
system: z.string().array(),
|
||||
modelID: z.string(),
|
||||
providerID: z.string(),
|
||||
path: z.object({
|
||||
cwd: z.string(),
|
||||
root: z.string(),
|
||||
}),
|
||||
cost: z.number(),
|
||||
summary: z.boolean().optional(),
|
||||
tokens: z.object({
|
||||
input: z.number(),
|
||||
output: z.number(),
|
||||
reasoning: z.number(),
|
||||
cache: z.object({
|
||||
read: z.number(),
|
||||
write: z.number(),
|
||||
}),
|
||||
}),
|
||||
})
|
||||
.optional(),
|
||||
}),
|
||||
.optional(),
|
||||
})
|
||||
.openapi({ ref: "Message.Metadata" }),
|
||||
})
|
||||
.openapi({
|
||||
ref: "Message.Info",
|
||||
|
||||
@@ -3,6 +3,7 @@ import path from "path"
|
||||
import { Tool } from "./tool"
|
||||
import { App } from "../app/app"
|
||||
import DESCRIPTION from "./glob.txt"
|
||||
import { Ripgrep } from "../external/ripgrep"
|
||||
|
||||
export const GlobTool = Tool.define({
|
||||
id: "glob",
|
||||
@@ -24,10 +25,12 @@ export const GlobTool = Tool.define({
|
||||
: path.resolve(app.path.cwd, search)
|
||||
|
||||
const limit = 100
|
||||
const glob = new Bun.Glob(params.pattern)
|
||||
const files = []
|
||||
let truncated = false
|
||||
for await (const file of glob.scan({ cwd: search, dot: true })) {
|
||||
for (const file of await Ripgrep.files({
|
||||
cwd: search,
|
||||
glob: params.pattern,
|
||||
})) {
|
||||
if (files.length >= limit) {
|
||||
truncated = true
|
||||
break
|
||||
|
||||
@@ -6,11 +6,13 @@ import (
|
||||
"path/filepath"
|
||||
"sort"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"log/slog"
|
||||
|
||||
tea "github.com/charmbracelet/bubbletea/v2"
|
||||
"github.com/sst/opencode/internal/commands"
|
||||
"github.com/sst/opencode/internal/components/toast"
|
||||
"github.com/sst/opencode/internal/config"
|
||||
"github.com/sst/opencode/internal/theme"
|
||||
"github.com/sst/opencode/internal/util"
|
||||
@@ -47,6 +49,9 @@ type SendMsg struct {
|
||||
type CompletionDialogTriggeredMsg struct {
|
||||
InitialValue string
|
||||
}
|
||||
type OptimisticMessageAddedMsg struct {
|
||||
Message client.MessageInfo
|
||||
}
|
||||
|
||||
func New(
|
||||
ctx context.Context,
|
||||
@@ -297,19 +302,12 @@ func (a *App) SendChatMessage(ctx context.Context, text string, attachments []At
|
||||
if a.Session.Id == "" {
|
||||
session, err := a.CreateSession(ctx)
|
||||
if err != nil {
|
||||
// status.Error(err.Error())
|
||||
return nil
|
||||
return toast.NewErrorToast(err.Error())
|
||||
}
|
||||
a.Session = session
|
||||
cmds = append(cmds, util.CmdHandler(SessionSelectedMsg(session)))
|
||||
}
|
||||
|
||||
// TODO: Handle attachments when API supports them
|
||||
if len(attachments) > 0 {
|
||||
// For now, ignore attachments
|
||||
// return "", fmt.Errorf("attachments not supported yet")
|
||||
}
|
||||
|
||||
part := client.MessagePart{}
|
||||
part.FromMessagePartText(client.MessagePartText{
|
||||
Type: "text",
|
||||
@@ -317,7 +315,26 @@ func (a *App) SendChatMessage(ctx context.Context, text string, attachments []At
|
||||
})
|
||||
parts := []client.MessagePart{part}
|
||||
|
||||
go func() {
|
||||
optimisticMessage := client.MessageInfo{
|
||||
Id: fmt.Sprintf("optimistic-%d", time.Now().UnixNano()),
|
||||
Role: client.User,
|
||||
Parts: parts,
|
||||
Metadata: client.MessageMetadata{
|
||||
SessionID: a.Session.Id,
|
||||
Time: struct {
|
||||
Completed *float32 `json:"completed,omitempty"`
|
||||
Created float32 `json:"created"`
|
||||
}{
|
||||
Created: float32(time.Now().Unix()),
|
||||
},
|
||||
Tool: make(map[string]client.MessageMetadata_Tool_AdditionalProperties),
|
||||
},
|
||||
}
|
||||
|
||||
a.Messages = append(a.Messages, optimisticMessage)
|
||||
cmds = append(cmds, util.CmdHandler(OptimisticMessageAddedMsg{Message: optimisticMessage}))
|
||||
|
||||
cmds = append(cmds, func() tea.Msg {
|
||||
response, err := a.Client.PostSessionChat(ctx, client.PostSessionChatJSONRequestBody{
|
||||
SessionID: a.Session.Id,
|
||||
Parts: parts,
|
||||
@@ -325,14 +342,17 @@ func (a *App) SendChatMessage(ctx context.Context, text string, attachments []At
|
||||
ModelID: a.Model.Id,
|
||||
})
|
||||
if err != nil {
|
||||
slog.Error("Failed to send message", "error", err)
|
||||
// status.Error(err.Error())
|
||||
errormsg := fmt.Sprintf("failed to send message: %v", err)
|
||||
slog.Error(errormsg)
|
||||
return toast.NewErrorToast(errormsg)()
|
||||
}
|
||||
if response != nil && response.StatusCode != 200 {
|
||||
slog.Error("Failed to send message", "error", fmt.Sprintf("failed to send message: %d", response.StatusCode))
|
||||
// status.Error(fmt.Sprintf("failed to send message: %d", response.StatusCode))
|
||||
errormsg := fmt.Sprintf("failed to send message: %d", response.StatusCode)
|
||||
slog.Error(errormsg)
|
||||
return toast.NewErrorToast(errormsg)()
|
||||
}
|
||||
}()
|
||||
return nil
|
||||
})
|
||||
|
||||
// The actual response will come through SSE
|
||||
// For now, just return success
|
||||
|
||||
@@ -25,8 +25,6 @@ import (
|
||||
func toMarkdown(content string, width int, backgroundColor compat.AdaptiveColor) string {
|
||||
r := styles.GetMarkdownRenderer(width, backgroundColor)
|
||||
content = strings.ReplaceAll(content, app.RootPath+"/", "")
|
||||
content = strings.ReplaceAll(content, "<", "\\<")
|
||||
content = strings.ReplaceAll(content, ">", "\\>")
|
||||
rendered, _ := r.Render(content)
|
||||
lines := strings.Split(rendered, "\n")
|
||||
|
||||
@@ -228,7 +226,11 @@ func renderText(message client.MessageInfo, text string, author string) string {
|
||||
textWidth := max(lipgloss.Width(text), lipgloss.Width(info))
|
||||
markdownWidth := min(textWidth, width-padding-4) // -4 for the border and padding
|
||||
if message.Role == client.Assistant {
|
||||
markdownWidth = width - padding - 4
|
||||
markdownWidth = width - padding - 4 - 2
|
||||
}
|
||||
if message.Role == client.User {
|
||||
text = strings.ReplaceAll(text, "<", "\\<")
|
||||
text = strings.ReplaceAll(text, ">", "\\>")
|
||||
}
|
||||
content := toMarkdown(text, markdownWidth, t.BackgroundPanel())
|
||||
content = strings.Join([]string{content, info}, "\n")
|
||||
@@ -251,7 +253,7 @@ func renderText(message client.MessageInfo, text string, author string) string {
|
||||
func renderToolInvocation(
|
||||
toolCall client.MessageToolInvocationToolCall,
|
||||
result *string,
|
||||
metadata client.MessageInfo_Metadata_Tool_AdditionalProperties,
|
||||
metadata client.MessageMetadata_Tool_AdditionalProperties,
|
||||
showDetails bool,
|
||||
isLast bool,
|
||||
contentOnly bool,
|
||||
@@ -464,7 +466,7 @@ func renderToolInvocation(
|
||||
|
||||
if metadata, ok := call["metadata"].(map[string]any); ok {
|
||||
data, _ = json.Marshal(metadata)
|
||||
var toolMetadata client.MessageInfo_Metadata_Tool_AdditionalProperties
|
||||
var toolMetadata client.MessageMetadata_Tool_AdditionalProperties
|
||||
_ = json.Unmarshal(data, &toolMetadata)
|
||||
|
||||
step := renderToolInvocation(
|
||||
|
||||
@@ -58,6 +58,12 @@ func (m *messagesComponent) Update(msg tea.Msg) (tea.Model, tea.Cmd) {
|
||||
m.viewport.GotoBottom()
|
||||
m.tail = true
|
||||
return m, nil
|
||||
case app.OptimisticMessageAddedMsg:
|
||||
m.renderView()
|
||||
if m.tail {
|
||||
m.viewport.GotoBottom()
|
||||
}
|
||||
return m, nil
|
||||
case dialog.ThemeSelectedMsg:
|
||||
m.cache.Clear()
|
||||
return m, m.Reload()
|
||||
@@ -171,7 +177,7 @@ func (m *messagesComponent) renderView() {
|
||||
isLastToolInvocation := slices.Contains(lastToolIndices, i)
|
||||
toolInvocationPart := part.(client.MessagePartToolInvocation)
|
||||
toolCall, _ := toolInvocationPart.ToolInvocation.AsMessageToolInvocationToolCall()
|
||||
metadata := client.MessageInfo_Metadata_Tool_AdditionalProperties{}
|
||||
metadata := client.MessageMetadata_Tool_AdditionalProperties{}
|
||||
if _, ok := message.Metadata.Tool[toolCall.ToolCallId]; ok {
|
||||
metadata = message.Metadata.Tool[toolCall.ToolCallId]
|
||||
}
|
||||
|
||||
@@ -111,8 +111,14 @@ func PlaceOverlay(
|
||||
fgLineWidth := ansi.PrintableRuneWidth(fgLine)
|
||||
|
||||
// Extract the styles at the border positions
|
||||
leftStyle := getStyleAtPosition(bgLine, pos)
|
||||
rightStyle := getStyleAtPosition(bgLine, pos+1+fgLineWidth)
|
||||
// We need to get the style just before the border position to preserve background
|
||||
leftStyle := ansiStyle{}
|
||||
if pos > 0 {
|
||||
leftStyle = getStyleAtPosition(bgLine, pos-1)
|
||||
} else {
|
||||
leftStyle = getStyleAtPosition(bgLine, pos)
|
||||
}
|
||||
rightStyle := getStyleAtPosition(bgLine, pos+fgLineWidth)
|
||||
|
||||
// Left border - combine background from original with border foreground
|
||||
leftSeq := combineStyles(leftStyle, options.borderColor)
|
||||
@@ -120,7 +126,9 @@ func PlaceOverlay(
|
||||
b.WriteString(leftSeq)
|
||||
}
|
||||
b.WriteString("┃")
|
||||
b.WriteString("\x1b[0m") // Reset all styles
|
||||
if leftSeq != "" {
|
||||
b.WriteString("\x1b[0m") // Reset all styles only if we applied any
|
||||
}
|
||||
pos++
|
||||
|
||||
// Content
|
||||
@@ -133,7 +141,9 @@ func PlaceOverlay(
|
||||
b.WriteString(rightSeq)
|
||||
}
|
||||
b.WriteString("┃")
|
||||
b.WriteString("\x1b[0m") // Reset all styles
|
||||
if rightSeq != "" {
|
||||
b.WriteString("\x1b[0m") // Reset all styles only if we applied any
|
||||
}
|
||||
pos++
|
||||
} else {
|
||||
// No border, just render the content
|
||||
@@ -188,7 +198,9 @@ func parseANSISequence(seq string) ansiStyle {
|
||||
for i < len(parts) {
|
||||
switch parts[i] {
|
||||
case "0": // Reset
|
||||
style = ansiStyle{}
|
||||
// Mark this as a reset by adding it to attrs
|
||||
style.attrs = append(style.attrs, "0")
|
||||
// Don't clear the style here, let the caller handle it
|
||||
case "1", "2", "3", "4", "5", "6", "7", "8", "9": // Various attributes
|
||||
style.attrs = append(style.attrs, parts[i])
|
||||
case "38": // Foreground color
|
||||
@@ -244,11 +256,9 @@ func combineStyles(bgStyle ansiStyle, fgColor *compat.AdaptiveColor) string {
|
||||
|
||||
// Add foreground color if specified
|
||||
if fgColor != nil {
|
||||
// Use the light color (could be improved to detect terminal background)
|
||||
color := (*fgColor).Light
|
||||
|
||||
// Use RGBA to get color components
|
||||
r, g, b, _ := color.RGBA()
|
||||
// Use the adaptive color which automatically selects based on terminal background
|
||||
// The RGBA method already handles light/dark selection
|
||||
r, g, b, _ := fgColor.RGBA()
|
||||
// RGBA returns 16-bit values, we need 8-bit
|
||||
parts = append(parts, fmt.Sprintf("38;2;%d;%d;%d", r>>8, g>>8, b>>8))
|
||||
}
|
||||
@@ -276,15 +286,21 @@ func getStyleAtPosition(s string, targetPos int) ansiStyle {
|
||||
seq := s[i : i+match[1]]
|
||||
parsedStyle := parseANSISequence(seq)
|
||||
|
||||
// Update current style (merge with existing)
|
||||
if parsedStyle.fgColor != "" {
|
||||
currentStyle.fgColor = parsedStyle.fgColor
|
||||
}
|
||||
if parsedStyle.bgColor != "" {
|
||||
currentStyle.bgColor = parsedStyle.bgColor
|
||||
}
|
||||
if len(parsedStyle.attrs) > 0 {
|
||||
currentStyle.attrs = parsedStyle.attrs
|
||||
// Check if this is a reset sequence
|
||||
if len(parsedStyle.attrs) > 0 && parsedStyle.attrs[0] == "0" {
|
||||
// Reset all styles
|
||||
currentStyle = ansiStyle{}
|
||||
} else {
|
||||
// Update current style (merge with existing)
|
||||
if parsedStyle.fgColor != "" {
|
||||
currentStyle.fgColor = parsedStyle.fgColor
|
||||
}
|
||||
if parsedStyle.bgColor != "" {
|
||||
currentStyle.bgColor = parsedStyle.bgColor
|
||||
}
|
||||
if len(parsedStyle.attrs) > 0 {
|
||||
currentStyle.attrs = parsedStyle.attrs
|
||||
}
|
||||
}
|
||||
|
||||
i += match[1]
|
||||
|
||||
@@ -189,7 +189,7 @@ func (a appModel) Update(msg tea.Msg) (tea.Model, tea.Cmd) {
|
||||
updated, cmd := a.messages.Update(msg)
|
||||
a.messages = updated.(chat.MessagesComponent)
|
||||
cmds = append(cmds, cmd)
|
||||
return a, tea.Batch(cmds...)
|
||||
return a, tea.Batch(cmds...)
|
||||
case tea.BackgroundColorMsg:
|
||||
styles.Terminal = &styles.TerminalInfo{
|
||||
BackgroundIsDark: msg.IsDark(),
|
||||
@@ -230,12 +230,33 @@ func (a appModel) Update(msg tea.Msg) (tea.Model, tea.Cmd) {
|
||||
case client.EventMessageUpdated:
|
||||
if msg.Properties.Info.Metadata.SessionID == a.app.Session.Id {
|
||||
exists := false
|
||||
for i, m := range a.app.Messages {
|
||||
if m.Id == msg.Properties.Info.Id {
|
||||
a.app.Messages[i] = msg.Properties.Info
|
||||
exists = true
|
||||
optimisticReplaced := false
|
||||
|
||||
// First check if this is replacing an optimistic message
|
||||
if msg.Properties.Info.Role == client.User {
|
||||
// Look for optimistic messages to replace
|
||||
for i, m := range a.app.Messages {
|
||||
if strings.HasPrefix(m.Id, "optimistic-") && m.Role == client.User {
|
||||
// Replace the optimistic message with the real one
|
||||
a.app.Messages[i] = msg.Properties.Info
|
||||
exists = true
|
||||
optimisticReplaced = true
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// If not replacing optimistic, check for existing message with same ID
|
||||
if !optimisticReplaced {
|
||||
for i, m := range a.app.Messages {
|
||||
if m.Id == msg.Properties.Info.Id {
|
||||
a.app.Messages[i] = msg.Properties.Info
|
||||
exists = true
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if !exists {
|
||||
a.app.Messages = append(a.app.Messages, msg.Properties.Info)
|
||||
}
|
||||
|
||||
@@ -230,6 +230,42 @@
|
||||
}
|
||||
}
|
||||
},
|
||||
"/session_unshare": {
|
||||
"post": {
|
||||
"responses": {
|
||||
"200": {
|
||||
"description": "Successfully unshared session",
|
||||
"content": {
|
||||
"application/json": {
|
||||
"schema": {
|
||||
"$ref": "#/components/schemas/session.info"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"operationId": "postSession_unshare",
|
||||
"parameters": [],
|
||||
"description": "Unshare the session",
|
||||
"requestBody": {
|
||||
"content": {
|
||||
"application/json": {
|
||||
"schema": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"sessionID": {
|
||||
"type": "string"
|
||||
}
|
||||
},
|
||||
"required": [
|
||||
"sessionID"
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"/session_messages": {
|
||||
"post": {
|
||||
"responses": {
|
||||
@@ -734,160 +770,7 @@
|
||||
}
|
||||
},
|
||||
"metadata": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"time": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"created": {
|
||||
"type": "number"
|
||||
},
|
||||
"completed": {
|
||||
"type": "number"
|
||||
}
|
||||
},
|
||||
"required": [
|
||||
"created"
|
||||
]
|
||||
},
|
||||
"error": {
|
||||
"oneOf": [
|
||||
{
|
||||
"$ref": "#/components/schemas/ProviderAuthError"
|
||||
},
|
||||
{
|
||||
"$ref": "#/components/schemas/UnknownError"
|
||||
}
|
||||
],
|
||||
"discriminator": {
|
||||
"propertyName": "name",
|
||||
"mapping": {
|
||||
"ProviderAuthError": "#/components/schemas/ProviderAuthError",
|
||||
"UnknownError": "#/components/schemas/UnknownError"
|
||||
}
|
||||
}
|
||||
},
|
||||
"sessionID": {
|
||||
"type": "string"
|
||||
},
|
||||
"tool": {
|
||||
"type": "object",
|
||||
"additionalProperties": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"title": {
|
||||
"type": "string"
|
||||
},
|
||||
"time": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"start": {
|
||||
"type": "number"
|
||||
},
|
||||
"end": {
|
||||
"type": "number"
|
||||
}
|
||||
},
|
||||
"required": [
|
||||
"start",
|
||||
"end"
|
||||
]
|
||||
}
|
||||
},
|
||||
"required": [
|
||||
"title",
|
||||
"time"
|
||||
],
|
||||
"additionalProperties": {}
|
||||
}
|
||||
},
|
||||
"assistant": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"system": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
"type": "string"
|
||||
}
|
||||
},
|
||||
"modelID": {
|
||||
"type": "string"
|
||||
},
|
||||
"providerID": {
|
||||
"type": "string"
|
||||
},
|
||||
"path": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"cwd": {
|
||||
"type": "string"
|
||||
},
|
||||
"root": {
|
||||
"type": "string"
|
||||
}
|
||||
},
|
||||
"required": [
|
||||
"cwd",
|
||||
"root"
|
||||
]
|
||||
},
|
||||
"cost": {
|
||||
"type": "number"
|
||||
},
|
||||
"summary": {
|
||||
"type": "boolean"
|
||||
},
|
||||
"tokens": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"input": {
|
||||
"type": "number"
|
||||
},
|
||||
"output": {
|
||||
"type": "number"
|
||||
},
|
||||
"reasoning": {
|
||||
"type": "number"
|
||||
},
|
||||
"cache": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"read": {
|
||||
"type": "number"
|
||||
},
|
||||
"write": {
|
||||
"type": "number"
|
||||
}
|
||||
},
|
||||
"required": [
|
||||
"read",
|
||||
"write"
|
||||
]
|
||||
}
|
||||
},
|
||||
"required": [
|
||||
"input",
|
||||
"output",
|
||||
"reasoning",
|
||||
"cache"
|
||||
]
|
||||
}
|
||||
},
|
||||
"required": [
|
||||
"system",
|
||||
"modelID",
|
||||
"providerID",
|
||||
"path",
|
||||
"cost",
|
||||
"tokens"
|
||||
]
|
||||
}
|
||||
},
|
||||
"required": [
|
||||
"time",
|
||||
"sessionID",
|
||||
"tool"
|
||||
]
|
||||
"$ref": "#/components/schemas/Message.Metadata"
|
||||
}
|
||||
},
|
||||
"required": [
|
||||
@@ -1141,6 +1024,162 @@
|
||||
"type"
|
||||
]
|
||||
},
|
||||
"Message.Metadata": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"time": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"created": {
|
||||
"type": "number"
|
||||
},
|
||||
"completed": {
|
||||
"type": "number"
|
||||
}
|
||||
},
|
||||
"required": [
|
||||
"created"
|
||||
]
|
||||
},
|
||||
"error": {
|
||||
"oneOf": [
|
||||
{
|
||||
"$ref": "#/components/schemas/ProviderAuthError"
|
||||
},
|
||||
{
|
||||
"$ref": "#/components/schemas/UnknownError"
|
||||
}
|
||||
],
|
||||
"discriminator": {
|
||||
"propertyName": "name",
|
||||
"mapping": {
|
||||
"ProviderAuthError": "#/components/schemas/ProviderAuthError",
|
||||
"UnknownError": "#/components/schemas/UnknownError"
|
||||
}
|
||||
}
|
||||
},
|
||||
"sessionID": {
|
||||
"type": "string"
|
||||
},
|
||||
"tool": {
|
||||
"type": "object",
|
||||
"additionalProperties": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"title": {
|
||||
"type": "string"
|
||||
},
|
||||
"time": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"start": {
|
||||
"type": "number"
|
||||
},
|
||||
"end": {
|
||||
"type": "number"
|
||||
}
|
||||
},
|
||||
"required": [
|
||||
"start",
|
||||
"end"
|
||||
]
|
||||
}
|
||||
},
|
||||
"required": [
|
||||
"title",
|
||||
"time"
|
||||
],
|
||||
"additionalProperties": {}
|
||||
}
|
||||
},
|
||||
"assistant": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"system": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
"type": "string"
|
||||
}
|
||||
},
|
||||
"modelID": {
|
||||
"type": "string"
|
||||
},
|
||||
"providerID": {
|
||||
"type": "string"
|
||||
},
|
||||
"path": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"cwd": {
|
||||
"type": "string"
|
||||
},
|
||||
"root": {
|
||||
"type": "string"
|
||||
}
|
||||
},
|
||||
"required": [
|
||||
"cwd",
|
||||
"root"
|
||||
]
|
||||
},
|
||||
"cost": {
|
||||
"type": "number"
|
||||
},
|
||||
"summary": {
|
||||
"type": "boolean"
|
||||
},
|
||||
"tokens": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"input": {
|
||||
"type": "number"
|
||||
},
|
||||
"output": {
|
||||
"type": "number"
|
||||
},
|
||||
"reasoning": {
|
||||
"type": "number"
|
||||
},
|
||||
"cache": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"read": {
|
||||
"type": "number"
|
||||
},
|
||||
"write": {
|
||||
"type": "number"
|
||||
}
|
||||
},
|
||||
"required": [
|
||||
"read",
|
||||
"write"
|
||||
]
|
||||
}
|
||||
},
|
||||
"required": [
|
||||
"input",
|
||||
"output",
|
||||
"reasoning",
|
||||
"cache"
|
||||
]
|
||||
}
|
||||
},
|
||||
"required": [
|
||||
"system",
|
||||
"modelID",
|
||||
"providerID",
|
||||
"path",
|
||||
"cost",
|
||||
"tokens"
|
||||
]
|
||||
}
|
||||
},
|
||||
"required": [
|
||||
"time",
|
||||
"sessionID",
|
||||
"tool"
|
||||
]
|
||||
},
|
||||
"ProviderAuthError": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
@@ -1461,6 +1500,9 @@
|
||||
"temperature": {
|
||||
"type": "boolean"
|
||||
},
|
||||
"tool_call": {
|
||||
"type": "boolean"
|
||||
},
|
||||
"cost": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
@@ -1499,6 +1541,10 @@
|
||||
},
|
||||
"id": {
|
||||
"type": "string"
|
||||
},
|
||||
"options": {
|
||||
"type": "object",
|
||||
"additionalProperties": {}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1535,7 +1581,8 @@
|
||||
},
|
||||
"description": "MCP (Model Context Protocol) server configurations"
|
||||
}
|
||||
}
|
||||
},
|
||||
"additionalProperties": false
|
||||
},
|
||||
"Config.Keybinds": {
|
||||
"type": "object",
|
||||
@@ -1648,7 +1695,8 @@
|
||||
"type": "string",
|
||||
"description": "Exit the application"
|
||||
}
|
||||
}
|
||||
},
|
||||
"additionalProperties": false
|
||||
},
|
||||
"Provider.Info": {
|
||||
"type": "object",
|
||||
@@ -1700,6 +1748,9 @@
|
||||
"temperature": {
|
||||
"type": "boolean"
|
||||
},
|
||||
"tool_call": {
|
||||
"type": "boolean"
|
||||
},
|
||||
"cost": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
@@ -1738,6 +1789,10 @@
|
||||
},
|
||||
"id": {
|
||||
"type": "string"
|
||||
},
|
||||
"options": {
|
||||
"type": "object",
|
||||
"additionalProperties": {}
|
||||
}
|
||||
},
|
||||
"required": [
|
||||
@@ -1745,9 +1800,11 @@
|
||||
"attachment",
|
||||
"reasoning",
|
||||
"temperature",
|
||||
"tool_call",
|
||||
"cost",
|
||||
"limit",
|
||||
"id"
|
||||
"id",
|
||||
"options"
|
||||
]
|
||||
},
|
||||
"Config.McpLocal": {
|
||||
@@ -1776,7 +1833,8 @@
|
||||
"required": [
|
||||
"type",
|
||||
"command"
|
||||
]
|
||||
],
|
||||
"additionalProperties": false
|
||||
},
|
||||
"Config.McpRemote": {
|
||||
"type": "object",
|
||||
@@ -1794,7 +1852,8 @@
|
||||
"required": [
|
||||
"type",
|
||||
"url"
|
||||
]
|
||||
],
|
||||
"additionalProperties": false
|
||||
},
|
||||
"Error": {
|
||||
"type": "object",
|
||||
|
||||
@@ -78,9 +78,11 @@ type ConfigInfo struct {
|
||||
Context float32 `json:"context"`
|
||||
Output float32 `json:"output"`
|
||||
} `json:"limit,omitempty"`
|
||||
Name *string `json:"name,omitempty"`
|
||||
Reasoning *bool `json:"reasoning,omitempty"`
|
||||
Temperature *bool `json:"temperature,omitempty"`
|
||||
Name *string `json:"name,omitempty"`
|
||||
Options *map[string]interface{} `json:"options,omitempty"`
|
||||
Reasoning *bool `json:"reasoning,omitempty"`
|
||||
Temperature *bool `json:"temperature,omitempty"`
|
||||
ToolCall *bool `json:"tool_call,omitempty"`
|
||||
} `json:"models"`
|
||||
Name *string `json:"name,omitempty"`
|
||||
Npm *string `json:"npm,omitempty"`
|
||||
@@ -290,47 +292,53 @@ type InstallationInfo struct {
|
||||
|
||||
// MessageInfo defines model for Message.Info.
|
||||
type MessageInfo struct {
|
||||
Id string `json:"id"`
|
||||
Metadata struct {
|
||||
Assistant *struct {
|
||||
Cost float32 `json:"cost"`
|
||||
ModelID string `json:"modelID"`
|
||||
Path struct {
|
||||
Cwd string `json:"cwd"`
|
||||
Root string `json:"root"`
|
||||
} `json:"path"`
|
||||
ProviderID string `json:"providerID"`
|
||||
Summary *bool `json:"summary,omitempty"`
|
||||
System []string `json:"system"`
|
||||
Tokens struct {
|
||||
Cache struct {
|
||||
Read float32 `json:"read"`
|
||||
Write float32 `json:"write"`
|
||||
} `json:"cache"`
|
||||
Input float32 `json:"input"`
|
||||
Output float32 `json:"output"`
|
||||
Reasoning float32 `json:"reasoning"`
|
||||
} `json:"tokens"`
|
||||
} `json:"assistant,omitempty"`
|
||||
Error *MessageInfo_Metadata_Error `json:"error,omitempty"`
|
||||
SessionID string `json:"sessionID"`
|
||||
Time struct {
|
||||
Completed *float32 `json:"completed,omitempty"`
|
||||
Created float32 `json:"created"`
|
||||
} `json:"time"`
|
||||
Tool map[string]MessageInfo_Metadata_Tool_AdditionalProperties `json:"tool"`
|
||||
} `json:"metadata"`
|
||||
Parts []MessagePart `json:"parts"`
|
||||
Role MessageInfoRole `json:"role"`
|
||||
Id string `json:"id"`
|
||||
Metadata MessageMetadata `json:"metadata"`
|
||||
Parts []MessagePart `json:"parts"`
|
||||
Role MessageInfoRole `json:"role"`
|
||||
}
|
||||
|
||||
// MessageInfo_Metadata_Error defines model for MessageInfo.Metadata.Error.
|
||||
type MessageInfo_Metadata_Error struct {
|
||||
// MessageInfoRole defines model for MessageInfo.Role.
|
||||
type MessageInfoRole string
|
||||
|
||||
// MessageMetadata defines model for Message.Metadata.
|
||||
type MessageMetadata struct {
|
||||
Assistant *struct {
|
||||
Cost float32 `json:"cost"`
|
||||
ModelID string `json:"modelID"`
|
||||
Path struct {
|
||||
Cwd string `json:"cwd"`
|
||||
Root string `json:"root"`
|
||||
} `json:"path"`
|
||||
ProviderID string `json:"providerID"`
|
||||
Summary *bool `json:"summary,omitempty"`
|
||||
System []string `json:"system"`
|
||||
Tokens struct {
|
||||
Cache struct {
|
||||
Read float32 `json:"read"`
|
||||
Write float32 `json:"write"`
|
||||
} `json:"cache"`
|
||||
Input float32 `json:"input"`
|
||||
Output float32 `json:"output"`
|
||||
Reasoning float32 `json:"reasoning"`
|
||||
} `json:"tokens"`
|
||||
} `json:"assistant,omitempty"`
|
||||
Error *MessageMetadata_Error `json:"error,omitempty"`
|
||||
SessionID string `json:"sessionID"`
|
||||
Time struct {
|
||||
Completed *float32 `json:"completed,omitempty"`
|
||||
Created float32 `json:"created"`
|
||||
} `json:"time"`
|
||||
Tool map[string]MessageMetadata_Tool_AdditionalProperties `json:"tool"`
|
||||
}
|
||||
|
||||
// MessageMetadata_Error defines model for MessageMetadata.Error.
|
||||
type MessageMetadata_Error struct {
|
||||
union json.RawMessage
|
||||
}
|
||||
|
||||
// MessageInfo_Metadata_Tool_AdditionalProperties defines model for MessageInfo.Metadata.Tool.AdditionalProperties.
|
||||
type MessageInfo_Metadata_Tool_AdditionalProperties struct {
|
||||
// MessageMetadata_Tool_AdditionalProperties defines model for Message.Metadata.tool.AdditionalProperties.
|
||||
type MessageMetadata_Tool_AdditionalProperties struct {
|
||||
Time struct {
|
||||
End float32 `json:"end"`
|
||||
Start float32 `json:"start"`
|
||||
@@ -339,9 +347,6 @@ type MessageInfo_Metadata_Tool_AdditionalProperties struct {
|
||||
AdditionalProperties map[string]interface{} `json:"-"`
|
||||
}
|
||||
|
||||
// MessageInfoRole defines model for MessageInfo.Role.
|
||||
type MessageInfoRole string
|
||||
|
||||
// MessagePart defines model for Message.Part.
|
||||
type MessagePart struct {
|
||||
union json.RawMessage
|
||||
@@ -435,9 +440,11 @@ type ModelInfo struct {
|
||||
Context float32 `json:"context"`
|
||||
Output float32 `json:"output"`
|
||||
} `json:"limit"`
|
||||
Name string `json:"name"`
|
||||
Reasoning bool `json:"reasoning"`
|
||||
Temperature bool `json:"temperature"`
|
||||
Name string `json:"name"`
|
||||
Options map[string]interface{} `json:"options"`
|
||||
Reasoning bool `json:"reasoning"`
|
||||
Temperature bool `json:"temperature"`
|
||||
ToolCall bool `json:"tool_call"`
|
||||
}
|
||||
|
||||
// ProviderInfo defines model for Provider.Info.
|
||||
@@ -535,6 +542,11 @@ type PostSessionSummarizeJSONBody struct {
|
||||
SessionID string `json:"sessionID"`
|
||||
}
|
||||
|
||||
// PostSessionUnshareJSONBody defines parameters for PostSessionUnshare.
|
||||
type PostSessionUnshareJSONBody struct {
|
||||
SessionID string `json:"sessionID"`
|
||||
}
|
||||
|
||||
// PostFileSearchJSONRequestBody defines body for PostFileSearch for application/json ContentType.
|
||||
type PostFileSearchJSONRequestBody PostFileSearchJSONBody
|
||||
|
||||
@@ -556,25 +568,28 @@ type PostSessionShareJSONRequestBody PostSessionShareJSONBody
|
||||
// PostSessionSummarizeJSONRequestBody defines body for PostSessionSummarize for application/json ContentType.
|
||||
type PostSessionSummarizeJSONRequestBody PostSessionSummarizeJSONBody
|
||||
|
||||
// Getter for additional properties for MessageInfo_Metadata_Tool_AdditionalProperties. Returns the specified
|
||||
// PostSessionUnshareJSONRequestBody defines body for PostSessionUnshare for application/json ContentType.
|
||||
type PostSessionUnshareJSONRequestBody PostSessionUnshareJSONBody
|
||||
|
||||
// Getter for additional properties for MessageMetadata_Tool_AdditionalProperties. Returns the specified
|
||||
// element and whether it was found
|
||||
func (a MessageInfo_Metadata_Tool_AdditionalProperties) Get(fieldName string) (value interface{}, found bool) {
|
||||
func (a MessageMetadata_Tool_AdditionalProperties) Get(fieldName string) (value interface{}, found bool) {
|
||||
if a.AdditionalProperties != nil {
|
||||
value, found = a.AdditionalProperties[fieldName]
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
// Setter for additional properties for MessageInfo_Metadata_Tool_AdditionalProperties
|
||||
func (a *MessageInfo_Metadata_Tool_AdditionalProperties) Set(fieldName string, value interface{}) {
|
||||
// Setter for additional properties for MessageMetadata_Tool_AdditionalProperties
|
||||
func (a *MessageMetadata_Tool_AdditionalProperties) Set(fieldName string, value interface{}) {
|
||||
if a.AdditionalProperties == nil {
|
||||
a.AdditionalProperties = make(map[string]interface{})
|
||||
}
|
||||
a.AdditionalProperties[fieldName] = value
|
||||
}
|
||||
|
||||
// Override default JSON handling for MessageInfo_Metadata_Tool_AdditionalProperties to handle AdditionalProperties
|
||||
func (a *MessageInfo_Metadata_Tool_AdditionalProperties) UnmarshalJSON(b []byte) error {
|
||||
// Override default JSON handling for MessageMetadata_Tool_AdditionalProperties to handle AdditionalProperties
|
||||
func (a *MessageMetadata_Tool_AdditionalProperties) UnmarshalJSON(b []byte) error {
|
||||
object := make(map[string]json.RawMessage)
|
||||
err := json.Unmarshal(b, &object)
|
||||
if err != nil {
|
||||
@@ -603,7 +618,7 @@ func (a *MessageInfo_Metadata_Tool_AdditionalProperties) UnmarshalJSON(b []byte)
|
||||
var fieldVal interface{}
|
||||
err := json.Unmarshal(fieldBuf, &fieldVal)
|
||||
if err != nil {
|
||||
return fmt.Errorf("error unmarshalling field %s: %w", fieldName, err)
|
||||
return fmt.Errorf("error unmarshaling field %s: %w", fieldName, err)
|
||||
}
|
||||
a.AdditionalProperties[fieldName] = fieldVal
|
||||
}
|
||||
@@ -611,8 +626,8 @@ func (a *MessageInfo_Metadata_Tool_AdditionalProperties) UnmarshalJSON(b []byte)
|
||||
return nil
|
||||
}
|
||||
|
||||
// Override default JSON handling for MessageInfo_Metadata_Tool_AdditionalProperties to handle AdditionalProperties
|
||||
func (a MessageInfo_Metadata_Tool_AdditionalProperties) MarshalJSON() ([]byte, error) {
|
||||
// Override default JSON handling for MessageMetadata_Tool_AdditionalProperties to handle AdditionalProperties
|
||||
func (a MessageMetadata_Tool_AdditionalProperties) MarshalJSON() ([]byte, error) {
|
||||
var err error
|
||||
object := make(map[string]json.RawMessage)
|
||||
|
||||
@@ -1082,23 +1097,23 @@ func (t *EventSessionError_Properties_Error) UnmarshalJSON(b []byte) error {
|
||||
return err
|
||||
}
|
||||
|
||||
// AsProviderAuthError returns the union data inside the MessageInfo_Metadata_Error as a ProviderAuthError
|
||||
func (t MessageInfo_Metadata_Error) AsProviderAuthError() (ProviderAuthError, error) {
|
||||
// AsProviderAuthError returns the union data inside the MessageMetadata_Error as a ProviderAuthError
|
||||
func (t MessageMetadata_Error) AsProviderAuthError() (ProviderAuthError, error) {
|
||||
var body ProviderAuthError
|
||||
err := json.Unmarshal(t.union, &body)
|
||||
return body, err
|
||||
}
|
||||
|
||||
// FromProviderAuthError overwrites any union data inside the MessageInfo_Metadata_Error as the provided ProviderAuthError
|
||||
func (t *MessageInfo_Metadata_Error) FromProviderAuthError(v ProviderAuthError) error {
|
||||
// FromProviderAuthError overwrites any union data inside the MessageMetadata_Error as the provided ProviderAuthError
|
||||
func (t *MessageMetadata_Error) FromProviderAuthError(v ProviderAuthError) error {
|
||||
v.Name = "ProviderAuthError"
|
||||
b, err := json.Marshal(v)
|
||||
t.union = b
|
||||
return err
|
||||
}
|
||||
|
||||
// MergeProviderAuthError performs a merge with any union data inside the MessageInfo_Metadata_Error, using the provided ProviderAuthError
|
||||
func (t *MessageInfo_Metadata_Error) MergeProviderAuthError(v ProviderAuthError) error {
|
||||
// MergeProviderAuthError performs a merge with any union data inside the MessageMetadata_Error, using the provided ProviderAuthError
|
||||
func (t *MessageMetadata_Error) MergeProviderAuthError(v ProviderAuthError) error {
|
||||
v.Name = "ProviderAuthError"
|
||||
b, err := json.Marshal(v)
|
||||
if err != nil {
|
||||
@@ -1110,23 +1125,23 @@ func (t *MessageInfo_Metadata_Error) MergeProviderAuthError(v ProviderAuthError)
|
||||
return err
|
||||
}
|
||||
|
||||
// AsUnknownError returns the union data inside the MessageInfo_Metadata_Error as a UnknownError
|
||||
func (t MessageInfo_Metadata_Error) AsUnknownError() (UnknownError, error) {
|
||||
// AsUnknownError returns the union data inside the MessageMetadata_Error as a UnknownError
|
||||
func (t MessageMetadata_Error) AsUnknownError() (UnknownError, error) {
|
||||
var body UnknownError
|
||||
err := json.Unmarshal(t.union, &body)
|
||||
return body, err
|
||||
}
|
||||
|
||||
// FromUnknownError overwrites any union data inside the MessageInfo_Metadata_Error as the provided UnknownError
|
||||
func (t *MessageInfo_Metadata_Error) FromUnknownError(v UnknownError) error {
|
||||
// FromUnknownError overwrites any union data inside the MessageMetadata_Error as the provided UnknownError
|
||||
func (t *MessageMetadata_Error) FromUnknownError(v UnknownError) error {
|
||||
v.Name = "UnknownError"
|
||||
b, err := json.Marshal(v)
|
||||
t.union = b
|
||||
return err
|
||||
}
|
||||
|
||||
// MergeUnknownError performs a merge with any union data inside the MessageInfo_Metadata_Error, using the provided UnknownError
|
||||
func (t *MessageInfo_Metadata_Error) MergeUnknownError(v UnknownError) error {
|
||||
// MergeUnknownError performs a merge with any union data inside the MessageMetadata_Error, using the provided UnknownError
|
||||
func (t *MessageMetadata_Error) MergeUnknownError(v UnknownError) error {
|
||||
v.Name = "UnknownError"
|
||||
b, err := json.Marshal(v)
|
||||
if err != nil {
|
||||
@@ -1138,7 +1153,7 @@ func (t *MessageInfo_Metadata_Error) MergeUnknownError(v UnknownError) error {
|
||||
return err
|
||||
}
|
||||
|
||||
func (t MessageInfo_Metadata_Error) Discriminator() (string, error) {
|
||||
func (t MessageMetadata_Error) Discriminator() (string, error) {
|
||||
var discriminator struct {
|
||||
Discriminator string `json:"name"`
|
||||
}
|
||||
@@ -1146,7 +1161,7 @@ func (t MessageInfo_Metadata_Error) Discriminator() (string, error) {
|
||||
return discriminator.Discriminator, err
|
||||
}
|
||||
|
||||
func (t MessageInfo_Metadata_Error) ValueByDiscriminator() (interface{}, error) {
|
||||
func (t MessageMetadata_Error) ValueByDiscriminator() (interface{}, error) {
|
||||
discriminator, err := t.Discriminator()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
@@ -1161,12 +1176,12 @@ func (t MessageInfo_Metadata_Error) ValueByDiscriminator() (interface{}, error)
|
||||
}
|
||||
}
|
||||
|
||||
func (t MessageInfo_Metadata_Error) MarshalJSON() ([]byte, error) {
|
||||
func (t MessageMetadata_Error) MarshalJSON() ([]byte, error) {
|
||||
b, err := t.union.MarshalJSON()
|
||||
return b, err
|
||||
}
|
||||
|
||||
func (t *MessageInfo_Metadata_Error) UnmarshalJSON(b []byte) error {
|
||||
func (t *MessageMetadata_Error) UnmarshalJSON(b []byte) error {
|
||||
err := t.union.UnmarshalJSON(b)
|
||||
return err
|
||||
}
|
||||
@@ -1633,6 +1648,11 @@ type ClientInterface interface {
|
||||
PostSessionSummarizeWithBody(ctx context.Context, contentType string, body io.Reader, reqEditors ...RequestEditorFn) (*http.Response, error)
|
||||
|
||||
PostSessionSummarize(ctx context.Context, body PostSessionSummarizeJSONRequestBody, reqEditors ...RequestEditorFn) (*http.Response, error)
|
||||
|
||||
// PostSessionUnshareWithBody request with any body
|
||||
PostSessionUnshareWithBody(ctx context.Context, contentType string, body io.Reader, reqEditors ...RequestEditorFn) (*http.Response, error)
|
||||
|
||||
PostSessionUnshare(ctx context.Context, body PostSessionUnshareJSONRequestBody, reqEditors ...RequestEditorFn) (*http.Response, error)
|
||||
}
|
||||
|
||||
func (c *Client) PostAppInfo(ctx context.Context, reqEditors ...RequestEditorFn) (*http.Response, error) {
|
||||
@@ -1911,6 +1931,30 @@ func (c *Client) PostSessionSummarize(ctx context.Context, body PostSessionSumma
|
||||
return c.Client.Do(req)
|
||||
}
|
||||
|
||||
func (c *Client) PostSessionUnshareWithBody(ctx context.Context, contentType string, body io.Reader, reqEditors ...RequestEditorFn) (*http.Response, error) {
|
||||
req, err := NewPostSessionUnshareRequestWithBody(c.Server, contentType, body)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
req = req.WithContext(ctx)
|
||||
if err := c.applyEditors(ctx, req, reqEditors); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return c.Client.Do(req)
|
||||
}
|
||||
|
||||
func (c *Client) PostSessionUnshare(ctx context.Context, body PostSessionUnshareJSONRequestBody, reqEditors ...RequestEditorFn) (*http.Response, error) {
|
||||
req, err := NewPostSessionUnshareRequest(c.Server, body)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
req = req.WithContext(ctx)
|
||||
if err := c.applyEditors(ctx, req, reqEditors); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return c.Client.Do(req)
|
||||
}
|
||||
|
||||
// NewPostAppInfoRequest generates requests for PostAppInfo
|
||||
func NewPostAppInfoRequest(server string) (*http.Request, error) {
|
||||
var err error
|
||||
@@ -2434,6 +2478,46 @@ func NewPostSessionSummarizeRequestWithBody(server string, contentType string, b
|
||||
return req, nil
|
||||
}
|
||||
|
||||
// NewPostSessionUnshareRequest calls the generic PostSessionUnshare builder with application/json body
|
||||
func NewPostSessionUnshareRequest(server string, body PostSessionUnshareJSONRequestBody) (*http.Request, error) {
|
||||
var bodyReader io.Reader
|
||||
buf, err := json.Marshal(body)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
bodyReader = bytes.NewReader(buf)
|
||||
return NewPostSessionUnshareRequestWithBody(server, "application/json", bodyReader)
|
||||
}
|
||||
|
||||
// NewPostSessionUnshareRequestWithBody generates requests for PostSessionUnshare with any type of body
|
||||
func NewPostSessionUnshareRequestWithBody(server string, contentType string, body io.Reader) (*http.Request, error) {
|
||||
var err error
|
||||
|
||||
serverURL, err := url.Parse(server)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
operationPath := fmt.Sprintf("/session_unshare")
|
||||
if operationPath[0] == '/' {
|
||||
operationPath = "." + operationPath
|
||||
}
|
||||
|
||||
queryURL, err := serverURL.Parse(operationPath)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
req, err := http.NewRequest("POST", queryURL.String(), body)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
req.Header.Add("Content-Type", contentType)
|
||||
|
||||
return req, nil
|
||||
}
|
||||
|
||||
func (c *Client) applyEditors(ctx context.Context, req *http.Request, additionalEditors []RequestEditorFn) error {
|
||||
for _, r := range c.RequestEditors {
|
||||
if err := r(ctx, req); err != nil {
|
||||
@@ -2538,6 +2622,11 @@ type ClientWithResponsesInterface interface {
|
||||
PostSessionSummarizeWithBodyWithResponse(ctx context.Context, contentType string, body io.Reader, reqEditors ...RequestEditorFn) (*PostSessionSummarizeResponse, error)
|
||||
|
||||
PostSessionSummarizeWithResponse(ctx context.Context, body PostSessionSummarizeJSONRequestBody, reqEditors ...RequestEditorFn) (*PostSessionSummarizeResponse, error)
|
||||
|
||||
// PostSessionUnshareWithBodyWithResponse request with any body
|
||||
PostSessionUnshareWithBodyWithResponse(ctx context.Context, contentType string, body io.Reader, reqEditors ...RequestEditorFn) (*PostSessionUnshareResponse, error)
|
||||
|
||||
PostSessionUnshareWithResponse(ctx context.Context, body PostSessionUnshareJSONRequestBody, reqEditors ...RequestEditorFn) (*PostSessionUnshareResponse, error)
|
||||
}
|
||||
|
||||
type PostAppInfoResponse struct {
|
||||
@@ -2901,6 +2990,28 @@ func (r PostSessionSummarizeResponse) StatusCode() int {
|
||||
return 0
|
||||
}
|
||||
|
||||
type PostSessionUnshareResponse struct {
|
||||
Body []byte
|
||||
HTTPResponse *http.Response
|
||||
JSON200 *SessionInfo
|
||||
}
|
||||
|
||||
// Status returns HTTPResponse.Status
|
||||
func (r PostSessionUnshareResponse) Status() string {
|
||||
if r.HTTPResponse != nil {
|
||||
return r.HTTPResponse.Status
|
||||
}
|
||||
return http.StatusText(0)
|
||||
}
|
||||
|
||||
// StatusCode returns HTTPResponse.StatusCode
|
||||
func (r PostSessionUnshareResponse) StatusCode() int {
|
||||
if r.HTTPResponse != nil {
|
||||
return r.HTTPResponse.StatusCode
|
||||
}
|
||||
return 0
|
||||
}
|
||||
|
||||
// PostAppInfoWithResponse request returning *PostAppInfoResponse
|
||||
func (c *ClientWithResponses) PostAppInfoWithResponse(ctx context.Context, reqEditors ...RequestEditorFn) (*PostAppInfoResponse, error) {
|
||||
rsp, err := c.PostAppInfo(ctx, reqEditors...)
|
||||
@@ -3101,6 +3212,23 @@ func (c *ClientWithResponses) PostSessionSummarizeWithResponse(ctx context.Conte
|
||||
return ParsePostSessionSummarizeResponse(rsp)
|
||||
}
|
||||
|
||||
// PostSessionUnshareWithBodyWithResponse request with arbitrary body returning *PostSessionUnshareResponse
|
||||
func (c *ClientWithResponses) PostSessionUnshareWithBodyWithResponse(ctx context.Context, contentType string, body io.Reader, reqEditors ...RequestEditorFn) (*PostSessionUnshareResponse, error) {
|
||||
rsp, err := c.PostSessionUnshareWithBody(ctx, contentType, body, reqEditors...)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return ParsePostSessionUnshareResponse(rsp)
|
||||
}
|
||||
|
||||
func (c *ClientWithResponses) PostSessionUnshareWithResponse(ctx context.Context, body PostSessionUnshareJSONRequestBody, reqEditors ...RequestEditorFn) (*PostSessionUnshareResponse, error) {
|
||||
rsp, err := c.PostSessionUnshare(ctx, body, reqEditors...)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return ParsePostSessionUnshareResponse(rsp)
|
||||
}
|
||||
|
||||
// ParsePostAppInfoResponse parses an HTTP response from a PostAppInfoWithResponse call
|
||||
func ParsePostAppInfoResponse(rsp *http.Response) (*PostAppInfoResponse, error) {
|
||||
bodyBytes, err := io.ReadAll(rsp.Body)
|
||||
@@ -3531,3 +3659,29 @@ func ParsePostSessionSummarizeResponse(rsp *http.Response) (*PostSessionSummariz
|
||||
|
||||
return response, nil
|
||||
}
|
||||
|
||||
// ParsePostSessionUnshareResponse parses an HTTP response from a PostSessionUnshareWithResponse call
|
||||
func ParsePostSessionUnshareResponse(rsp *http.Response) (*PostSessionUnshareResponse, error) {
|
||||
bodyBytes, err := io.ReadAll(rsp.Body)
|
||||
defer func() { _ = rsp.Body.Close() }()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
response := &PostSessionUnshareResponse{
|
||||
Body: bodyBytes,
|
||||
HTTPResponse: rsp,
|
||||
}
|
||||
|
||||
switch {
|
||||
case strings.Contains(rsp.Header.Get("Content-Type"), "json") && rsp.StatusCode == 200:
|
||||
var dest SessionInfo
|
||||
if err := json.Unmarshal(bodyBytes, &dest); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
response.JSON200 = &dest
|
||||
|
||||
}
|
||||
|
||||
return response, nil
|
||||
}
|
||||
|
||||
@@ -89,3 +89,21 @@ You can configure MCP servers you want to use through the `mcp` option.
|
||||
```
|
||||
|
||||
[Learn more here](/docs/mcp-servers).
|
||||
|
||||
---
|
||||
|
||||
### Disabled providers
|
||||
|
||||
You can disable providers that are loaded automatically through the `disabled_providers` option. This is useful when you want to prevent certain providers from being loaded even if their credentials are available.
|
||||
|
||||
```json title="opencode.json"
|
||||
{
|
||||
"$schema": "https://opencode.ai/config.json",
|
||||
"disabled_providers": ["openai", "gemini"]
|
||||
}
|
||||
```
|
||||
|
||||
The `disabled_providers` option accepts an array of provider IDs. When a provider is disabled:
|
||||
- It won't be loaded even if environment variables are set
|
||||
- It won't be loaded even if API keys are configured through `opencode auth login`
|
||||
- The provider's models won't appear in the model selection list
|
||||
|
||||
Reference in New Issue
Block a user