Compare commits

...
19 changed files with 170 additions and 42 deletions
+1
View File
@@ -77,3 +77,4 @@
| 2025-09-10 | 307,287 (+7,251) | 233,435 (+3,647) | 540,722 (+10,898) |
| 2025-09-11 | 314,083 (+6,796) | 237,356 (+3,921) | 551,439 (+10,717) |
| 2025-09-12 | 321,046 (+6,963) | 240,728 (+3,372) | 561,774 (+10,335) |
| 2025-09-13 | 324,894 (+3,848) | 245,539 (+4,811) | 570,433 (+8,659) |
+1 -1
View File
@@ -7,7 +7,7 @@
"dev:remote": "VITE_AUTH_URL=https://auth.dev.opencode.ai bun sst shell --stage=dev bun dev",
"build": "vinxi build && ../../packages/opencode/script/schema.ts ./.output/public/config.json",
"start": "vinxi start",
"version": "0.7.9"
"version": "0.8.0"
},
"dependencies": {
"@ibm/plex": "6.4.1",
+1 -1
View File
@@ -1,7 +1,7 @@
{
"$schema": "https://json.schemastore.org/package.json",
"name": "@opencode/cloud-core",
"version": "0.7.9",
"version": "0.8.0",
"private": true,
"type": "module",
"dependencies": {
+1 -1
View File
@@ -1,6 +1,6 @@
{
"name": "@opencode/cloud-function",
"version": "0.7.9",
"version": "0.8.0",
"$schema": "https://json.schemastore.org/package.json",
"private": true,
"type": "module",
+1 -1
View File
@@ -1,6 +1,6 @@
{
"name": "@opencode/cloud-scripts",
"version": "0.7.9",
"version": "0.8.0",
"$schema": "https://json.schemastore.org/package.json",
"private": true,
"type": "module",
+1 -1
View File
@@ -1,6 +1,6 @@
{
"name": "@opencode/function",
"version": "0.7.9",
"version": "0.8.0",
"$schema": "https://json.schemastore.org/package.json",
"private": true,
"type": "module",
+1 -1
View File
@@ -1,6 +1,6 @@
{
"$schema": "https://json.schemastore.org/package.json",
"version": "0.7.9",
"version": "0.8.0",
"name": "opencode",
"type": "module",
"private": true,
+4 -3
View File
@@ -123,14 +123,15 @@ export const TuiCommand = cmd({
const file = Bun.file(binary)
if (!(await file.exists())) {
await Bun.write(file, tui, { mode: 0o755 })
await fs.chmod(binary, 0o755)
if (process.platform !== "win32") await fs.chmod(binary, 0o755)
}
cmd = [binary]
}
if (!tui) {
const dir = Bun.fileURLToPath(new URL("../../../../tui/cmd/opencode", import.meta.url))
await $`go build -o ./dist/tui ./main.go`.cwd(dir)
cmd = [path.join(dir, "dist/tui")]
let binaryName = `./dist/tui${process.platform === "win32" ? ".exe" : ""}`
await $`go build -o ${binaryName} ./main.go`.cwd(dir)
cmd = [path.join(dir, binaryName)]
}
Log.Default.info("tui", {
cmd,
+2
View File
@@ -10,6 +10,7 @@ export namespace Command {
agent: z.string().optional(),
model: z.string().optional(),
template: z.string(),
subtask: z.boolean().optional(),
})
.openapi({
ref: "Command",
@@ -28,6 +29,7 @@ export namespace Command {
model: command.model,
description: command.description,
template: command.template,
subtask: command.subtask,
}
}
+1
View File
@@ -244,6 +244,7 @@ export namespace Config {
description: z.string().optional(),
agent: z.string().optional(),
model: z.string().optional(),
subtask: z.boolean().optional(),
})
export type Command = z.infer<typeof Command>
+1
View File
@@ -8,6 +8,7 @@ export namespace Flag {
export const OPENCODE_DISABLE_DEFAULT_PLUGINS = truthy("OPENCODE_DISABLE_DEFAULT_PLUGINS")
export const OPENCODE_DISABLE_LSP_DOWNLOAD = truthy("OPENCODE_DISABLE_LSP_DOWNLOAD")
export const OPENCODE_ENABLE_EXPERIMENTAL_MODELS = truthy("OPENCODE_ENABLE_EXPERIMENTAL_MODELS")
export const OPENCODE_DISABLE_AUTOCOMPACT = truthy("OPENCODE_DISABLE_AUTOCOMPACT")
function truthy(key: string) {
const value = process.env[key]?.toLowerCase()
+5 -1
View File
@@ -10,6 +10,7 @@ import { Bus } from "../bus"
import z from "zod"
import type { ModelsDev } from "../provider/models"
import { SessionPrompt } from "./prompt"
import { Flag } from "../flag/flag"
export namespace SessionCompaction {
export const Event = {
@@ -22,9 +23,12 @@ export namespace SessionCompaction {
}
export function isOverflow(input: { tokens: MessageV2.Assistant["tokens"]; model: ModelsDev.Model }) {
if (Flag.OPENCODE_DISABLE_AUTOCOMPACT) return false
const context = input.model.limit.context
if (context === 0) return false
const count = input.tokens.input + input.tokens.cache.read + input.tokens.output
const output = Math.min(input.model.limit.output, SessionPrompt.OUTPUT_TOKEN_MAX) || SessionPrompt.OUTPUT_TOKEN_MAX
const usable = input.model.limit.context - output
const usable = context - output
return count > usable
}
+124 -7
View File
@@ -38,6 +38,7 @@ import { MCP } from "../mcp"
import { LSP } from "../lsp"
import { ReadTool } from "../tool/read"
import { ListTool } from "../tool/ls"
import { TaskTool } from "../tool/task"
import { FileTime } from "../file/time"
import { Permission } from "../permission"
import { Snapshot } from "../snapshot"
@@ -278,7 +279,11 @@ export namespace SessionPrompt {
content: x,
}),
),
...MessageV2.toModelMessage(msgs.filter((m) => !(m.info.role === "assistant" && m.info.error))),
...MessageV2.toModelMessage(
msgs.filter(
(m) => !(m.info.role === "assistant" && m.info.error && !MessageV2.AbortedError.isInstance(m.info.error)),
),
),
],
tools: model.info.tool_call === false ? undefined : tools,
model: wrapLanguageModel({
@@ -1311,7 +1316,7 @@ export namespace SessionPrompt {
export async function command(input: CommandInput) {
log.info("command", input)
const command = await Command.get(input.command)
const agent = command.agent ?? input.agent ?? "build"
const agentName = command.agent ?? input.agent ?? "build"
let template = command.template.replace("$ARGUMENTS", input.arguments)
@@ -1381,22 +1386,134 @@ export namespace SessionPrompt {
return Provider.parseModel(command.model)
}
if (command.agent) {
const agent = await Agent.get(command.agent)
if (agent.model) {
return agent.model
const cmdAgent = await Agent.get(command.agent)
if (cmdAgent.model) {
return cmdAgent.model
}
}
if (input.model) {
return Provider.parseModel(input.model)
}
return undefined
return await Provider.defaultModel()
})()
const agent = await Agent.get(agentName)
if (agent.mode === "subagent" || command.subtask) {
using abort = lock(input.sessionID)
const userMsg: MessageV2.User = {
id: Identifier.ascending("message"),
sessionID: input.sessionID,
time: {
created: Date.now(),
},
role: "user",
}
await Session.updateMessage(userMsg)
const userPart: MessageV2.Part = {
type: "text",
id: Identifier.ascending("part"),
messageID: userMsg.id,
sessionID: input.sessionID,
text: "The following tool was executed by the user",
synthetic: true,
}
await Session.updatePart(userPart)
const assistantMsg: MessageV2.Assistant = {
id: Identifier.ascending("message"),
sessionID: input.sessionID,
system: [],
mode: agentName,
cost: 0,
path: {
cwd: Instance.directory,
root: Instance.worktree,
},
time: {
created: Date.now(),
},
role: "assistant",
tokens: {
input: 0,
output: 0,
reasoning: 0,
cache: { read: 0, write: 0 },
},
modelID: model.modelID,
providerID: model.providerID,
}
await Session.updateMessage(assistantMsg)
const args = {
description: "Consulting " + agent.name,
subagent_type: agent.name,
prompt: template,
}
const toolPart: MessageV2.ToolPart = {
type: "tool",
id: Identifier.ascending("part"),
messageID: assistantMsg.id,
sessionID: input.sessionID,
tool: "task",
callID: ulid(),
state: {
status: "running",
time: {
start: Date.now(),
},
input: {
description: args.description,
subagent_type: args.subagent_type,
// truncate prompt to preserve context
prompt: args.prompt.length > 100 ? args.prompt.substring(0, 97) + "..." : args.prompt,
},
},
}
await Session.updatePart(toolPart)
const result = await TaskTool.init().then((t) =>
t.execute(args, {
sessionID: input.sessionID,
abort: abort.signal,
agent: agent.name,
messageID: assistantMsg.id,
extra: {},
metadata: async (metadata) => {
if (toolPart.state.status === "running") {
toolPart.state.metadata = metadata.metadata
toolPart.state.title = metadata.title
await Session.updatePart(toolPart)
}
},
}),
)
assistantMsg.time.completed = Date.now()
await Session.updateMessage(assistantMsg)
if (toolPart.state.status === "running") {
toolPart.state = {
status: "completed",
time: {
...toolPart.state.time,
end: Date.now(),
},
input: toolPart.state.input,
title: "",
metadata: result.metadata,
output: result.output,
}
await Session.updatePart(toolPart)
}
return { info: assistantMsg, parts: [toolPart] }
}
return prompt({
sessionID: input.sessionID,
messageID: input.messageID,
model,
agent,
agent: agentName,
parts,
})
}
+1 -1
View File
@@ -1,7 +1,7 @@
{
"$schema": "https://json.schemastore.org/package.json",
"name": "@opencode-ai/plugin",
"version": "0.7.9",
"version": "0.8.0",
"type": "module",
"scripts": {
"typecheck": "tsc --noEmit"
+1 -1
View File
@@ -1,7 +1,7 @@
{
"$schema": "https://json.schemastore.org/package.json",
"name": "@opencode-ai/sdk",
"version": "0.7.9",
"version": "0.8.0",
"type": "module",
"scripts": {
"typecheck": "tsc --noEmit"
+22 -20
View File
@@ -29,6 +29,9 @@ export type Event =
| ({
type: "message.part.removed"
} & EventMessagePartRemoved)
| ({
type: "session.compacted"
} & EventSessionCompacted)
| ({
type: "permission.updated"
} & EventPermissionUpdated)
@@ -38,21 +41,18 @@ export type Event =
| ({
type: "file.edited"
} & EventFileEdited)
| ({
type: "session.idle"
} & EventSessionIdle)
| ({
type: "session.updated"
} & EventSessionUpdated)
| ({
type: "session.deleted"
} & EventSessionDeleted)
| ({
type: "session.idle"
} & EventSessionIdle)
| ({
type: "session.error"
} & EventSessionError)
| ({
type: "session.compacted"
} & EventSessionCompacted)
| ({
type: "server.connected"
} & EventServerConnected)
@@ -425,6 +425,13 @@ export type EventMessagePartRemoved = {
}
}
export type EventSessionCompacted = {
type: "session.compacted"
properties: {
sessionID: string
}
}
export type EventPermissionUpdated = {
type: "permission.updated"
properties: Permission
@@ -462,6 +469,13 @@ export type EventFileEdited = {
}
}
export type EventSessionIdle = {
type: "session.idle"
properties: {
sessionID: string
}
}
export type EventSessionUpdated = {
type: "session.updated"
properties: {
@@ -499,13 +513,6 @@ export type EventSessionDeleted = {
}
}
export type EventSessionIdle = {
type: "session.idle"
properties: {
sessionID: string
}
}
export type EventSessionError = {
type: "session.error"
properties: {
@@ -526,13 +533,6 @@ export type EventSessionError = {
}
}
export type EventSessionCompacted = {
type: "session.compacted"
properties: {
sessionID: string
}
}
export type EventServerConnected = {
type: "server.connected"
properties: {
@@ -571,6 +571,7 @@ export type Config = {
description?: string
agent?: string
model?: string
subtask?: boolean
}
}
plugin?: Array<string>
@@ -1156,6 +1157,7 @@ export type Command = {
agent?: string
model?: string
template: string
subtask?: boolean
}
export type Symbol = {
@@ -899,7 +899,6 @@ func (m *messagesComponent) renderHeader() string {
}
tokens = (usage.Input +
usage.Cache.Write +
usage.Cache.Read +
usage.Output +
usage.Reasoning)
}
+1 -1
View File
@@ -1,7 +1,7 @@
{
"name": "@opencode/web",
"type": "module",
"version": "0.7.9",
"version": "0.8.0",
"scripts": {
"dev": "astro dev",
"dev:remote": "sst shell --stage=dev --target=Web astro dev",
+1 -1
View File
@@ -2,7 +2,7 @@
"name": "opencode",
"displayName": "opencode",
"description": "opencode for VS Code",
"version": "0.7.9",
"version": "0.8.0",
"publisher": "sst-dev",
"repository": {
"type": "git",