refactor(core): move database schema ownership (#29068)
Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com>
This commit is contained in:
@@ -1,7 +1,7 @@
|
||||
import * as path from "path"
|
||||
import { Effect, Schema } from "effect"
|
||||
import * as Tool from "./tool"
|
||||
import { Bus } from "../bus"
|
||||
import { EventV2Bridge } from "@/event-v2-bridge"
|
||||
import { FileWatcher } from "../file/watcher"
|
||||
import { InstanceState } from "@/effect/instance-state"
|
||||
import { Patch } from "../patch"
|
||||
@@ -25,7 +25,7 @@ export const ApplyPatchTool = Tool.define(
|
||||
const lsp = yield* LSP.Service
|
||||
const afs = yield* AppFileSystem.Service
|
||||
const format = yield* Format.Service
|
||||
const bus = yield* Bus.Service
|
||||
const events = yield* EventV2Bridge.Service
|
||||
|
||||
const run = Effect.fn("ApplyPatchTool.execute")(function* (
|
||||
params: Schema.Schema.Type<typeof Parameters>,
|
||||
@@ -253,13 +253,13 @@ export const ApplyPatchTool = Tool.define(
|
||||
if (yield* format.file(edited)) {
|
||||
yield* Bom.syncFile(afs, edited, change.bom)
|
||||
}
|
||||
yield* bus.publish(File.Event.Edited, { file: edited })
|
||||
yield* events.publish(File.Event.Edited, { file: edited })
|
||||
}
|
||||
}
|
||||
|
||||
// Publish file change events
|
||||
for (const update of updates) {
|
||||
yield* bus.publish(FileWatcher.Event.Updated, update)
|
||||
yield* events.publish(FileWatcher.Event.Updated, update)
|
||||
}
|
||||
|
||||
// Notify LSP of file changes and collect diagnostics
|
||||
|
||||
@@ -11,7 +11,7 @@ import { createTwoFilesPatch, diffLines } from "diff"
|
||||
import DESCRIPTION from "./edit.txt"
|
||||
import { File } from "../file"
|
||||
import { FileWatcher } from "../file/watcher"
|
||||
import { Bus } from "../bus"
|
||||
import { EventV2Bridge } from "@/event-v2-bridge"
|
||||
import { Format } from "../format"
|
||||
import { InstanceState } from "@/effect/instance-state"
|
||||
import { Snapshot } from "@/snapshot"
|
||||
@@ -61,7 +61,7 @@ export const EditTool = Tool.define(
|
||||
const lsp = yield* LSP.Service
|
||||
const afs = yield* AppFileSystem.Service
|
||||
const format = yield* Format.Service
|
||||
const bus = yield* Bus.Service
|
||||
const events = yield* EventV2Bridge.Service
|
||||
|
||||
return {
|
||||
description: DESCRIPTION,
|
||||
@@ -108,8 +108,8 @@ export const EditTool = Tool.define(
|
||||
if (yield* format.file(filePath)) {
|
||||
contentNew = yield* Bom.syncFile(afs, filePath, desiredBom)
|
||||
}
|
||||
yield* bus.publish(File.Event.Edited, { file: filePath })
|
||||
yield* bus.publish(FileWatcher.Event.Updated, {
|
||||
yield* events.publish(File.Event.Edited, { file: filePath })
|
||||
yield* events.publish(FileWatcher.Event.Updated, {
|
||||
file: filePath,
|
||||
event: existed ? "change" : "add",
|
||||
})
|
||||
@@ -152,8 +152,8 @@ export const EditTool = Tool.define(
|
||||
if (yield* format.file(filePath)) {
|
||||
contentNew = yield* Bom.syncFile(afs, filePath, desiredBom)
|
||||
}
|
||||
yield* bus.publish(File.Event.Edited, { file: filePath })
|
||||
yield* bus.publish(FileWatcher.Event.Updated, {
|
||||
yield* events.publish(File.Event.Edited, { file: filePath })
|
||||
yield* events.publish(FileWatcher.Event.Updated, {
|
||||
file: filePath,
|
||||
event: "change",
|
||||
})
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
import path from "path"
|
||||
import { SessionLegacy } from "@opencode-ai/core/session/legacy"
|
||||
import { Effect, Schema } from "effect"
|
||||
import * as Tool from "./tool"
|
||||
import { Question } from "../question"
|
||||
@@ -49,7 +50,7 @@ export const PlanExitTool = Tool.define(
|
||||
const model =
|
||||
lastUser?.info.role === "user" && lastUser.info.model ? lastUser.info.model : yield* provider.defaultModel()
|
||||
|
||||
const msg: MessageV2.User = {
|
||||
const msg: SessionLegacy.User = {
|
||||
id: MessageID.ascending(),
|
||||
sessionID: ctx.sessionID,
|
||||
role: "user",
|
||||
@@ -65,7 +66,7 @@ export const PlanExitTool = Tool.define(
|
||||
type: "text",
|
||||
text: `The plan at ${plan} has been approved, you can now edit files. Execute the plan`,
|
||||
synthetic: true,
|
||||
} satisfies MessageV2.TextPart)
|
||||
} satisfies SessionLegacy.TextPart)
|
||||
|
||||
return {
|
||||
title: "Switching to build agent",
|
||||
|
||||
@@ -7,6 +7,7 @@ import { GlobTool } from "./glob"
|
||||
import { GrepTool } from "./grep"
|
||||
import { ReadTool } from "./read"
|
||||
import { TaskTool } from "./task"
|
||||
import { Database } from "@opencode-ai/core/database/database"
|
||||
import { TodoWriteTool } from "./todo"
|
||||
import { WebFetchTool } from "./webfetch"
|
||||
import { WriteTool } from "./write"
|
||||
@@ -20,7 +21,7 @@ import { Schema } from "effect"
|
||||
import z from "zod"
|
||||
import { Plugin } from "../plugin"
|
||||
import { Provider } from "@/provider/provider"
|
||||
import { ProviderID, type ModelID } from "../provider/schema"
|
||||
|
||||
import { WebSearchTool } from "./websearch"
|
||||
import { RepoCloneTool } from "./repo_clone"
|
||||
import { RepoOverviewTool } from "./repo_overview"
|
||||
@@ -45,7 +46,7 @@ import { Todo } from "../session/todo"
|
||||
import { LSP } from "@/lsp/lsp"
|
||||
import { Instruction } from "../session/instruction"
|
||||
import { AppFileSystem } from "@opencode-ai/core/filesystem"
|
||||
import { Bus } from "../bus"
|
||||
import { EventV2Bridge } from "@/event-v2-bridge"
|
||||
import { Agent } from "../agent/agent"
|
||||
import { Git } from "@/git"
|
||||
import { Skill } from "../skill"
|
||||
@@ -53,11 +54,12 @@ import { Permission } from "@/permission"
|
||||
import { Reference } from "@/reference/reference"
|
||||
import { BackgroundJob } from "@/background/job"
|
||||
import { RuntimeFlags } from "@/effect/runtime-flags"
|
||||
import { ProviderV2 } from "@opencode-ai/core/provider"
|
||||
|
||||
const log = Log.create({ service: "tool.registry" })
|
||||
|
||||
export function webSearchEnabled(providerID: ProviderID, flags = { exa: false, parallel: false }) {
|
||||
return providerID === ProviderID.opencode || flags.exa || flags.parallel
|
||||
export function webSearchEnabled(providerID: ProviderV2.ID, flags = { exa: false, parallel: false }) {
|
||||
return providerID === ProviderV2.ID.opencode || flags.exa || flags.parallel
|
||||
}
|
||||
|
||||
type TaskDef = Tool.InferDef<typeof TaskTool>
|
||||
@@ -74,7 +76,7 @@ export interface Interface {
|
||||
readonly ids: () => Effect.Effect<string[]>
|
||||
readonly all: () => Effect.Effect<Tool.Def[]>
|
||||
readonly named: () => Effect.Effect<{ task: TaskDef; read: ReadDef }>
|
||||
readonly tools: (model: { providerID: ProviderID; modelID: ModelID; agent: Agent.Info }) => Effect.Effect<Tool.Def[]>
|
||||
readonly tools: (model: { providerID: ProviderV2.ID; modelID: ProviderV2.ModelID; agent: Agent.Info }) => Effect.Effect<Tool.Def[]>
|
||||
}
|
||||
|
||||
export class Service extends Context.Service<Service, Interface>()("@opencode/ToolRegistry") {}
|
||||
@@ -97,13 +99,14 @@ export const layer: Layer.Layer<
|
||||
| LSP.Service
|
||||
| Instruction.Service
|
||||
| AppFileSystem.Service
|
||||
| Bus.Service
|
||||
| EventV2Bridge.Service
|
||||
| HttpClient.HttpClient
|
||||
| ChildProcessSpawner
|
||||
| Ripgrep.Service
|
||||
| Format.Service
|
||||
| Truncate.Service
|
||||
| RuntimeFlags.Service
|
||||
| Database.Service
|
||||
> = Layer.effect(
|
||||
Service,
|
||||
Effect.gen(function* () {
|
||||
@@ -386,14 +389,14 @@ export const defaultLayer = Layer.suspend(() =>
|
||||
Layer.provide(LSP.defaultLayer),
|
||||
Layer.provide(Instruction.defaultLayer),
|
||||
Layer.provide(AppFileSystem.defaultLayer),
|
||||
Layer.provide(Bus.layer),
|
||||
Layer.provide(EventV2Bridge.defaultLayer),
|
||||
Layer.provide(FetchHttpClient.layer),
|
||||
Layer.provide(Format.defaultLayer),
|
||||
Layer.provide(CrossSpawnSpawner.defaultLayer),
|
||||
Layer.provide(Ripgrep.defaultLayer),
|
||||
Layer.provide(Truncate.defaultLayer),
|
||||
)
|
||||
.pipe(Layer.provide(RuntimeFlags.defaultLayer)),
|
||||
.pipe(Layer.provide(Database.defaultLayer), Layer.provide(RuntimeFlags.defaultLayer)),
|
||||
)
|
||||
|
||||
function isZodType(value: unknown): value is z.ZodType {
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
import * as Tool from "./tool"
|
||||
import DESCRIPTION from "./task.txt"
|
||||
import { ToolJsonSchema } from "./json-schema"
|
||||
import { SessionLegacy } from "@opencode-ai/core/session/legacy"
|
||||
import { BackgroundJob } from "@/background/job"
|
||||
import { Session } from "@/session/session"
|
||||
import { SessionID, MessageID } from "../session/schema"
|
||||
@@ -12,11 +13,12 @@ import { Config } from "@/config/config"
|
||||
import { Cause, Effect, Exit, Schema, Scope } from "effect"
|
||||
import { EffectBridge } from "@/effect/bridge"
|
||||
import { RuntimeFlags } from "@/effect/runtime-flags"
|
||||
import { Database } from "@opencode-ai/core/database/database"
|
||||
|
||||
export interface TaskPromptOps {
|
||||
cancel(sessionID: SessionID): Effect.Effect<void>
|
||||
resolvePromptParts(template: string): Effect.Effect<SessionPrompt.PromptInput["parts"]>
|
||||
prompt(input: SessionPrompt.PromptInput): Effect.Effect<MessageV2.WithParts>
|
||||
prompt(input: SessionPrompt.PromptInput): Effect.Effect<SessionLegacy.WithParts>
|
||||
}
|
||||
|
||||
const id = "task"
|
||||
@@ -102,6 +104,7 @@ export const TaskTool = Tool.define(
|
||||
const sessions = yield* Session.Service
|
||||
const scope = yield* Scope.Scope
|
||||
const flags = yield* RuntimeFlags.Service
|
||||
const database = yield* Database.Service
|
||||
|
||||
const run = Effect.fn("TaskTool.execute")(function* (
|
||||
params: Schema.Schema.Type<typeof Parameters>,
|
||||
@@ -158,7 +161,10 @@ export const TaskTool = Tool.define(
|
||||
],
|
||||
}))
|
||||
|
||||
const msg = yield* MessageV2.get({ sessionID: ctx.sessionID, messageID: ctx.messageID }).pipe(Effect.orDie)
|
||||
const msg = yield* MessageV2.get({ sessionID: ctx.sessionID, messageID: ctx.messageID }).pipe(
|
||||
Effect.provideService(Database.Service, database),
|
||||
Effect.orDie,
|
||||
)
|
||||
if (msg.info.role !== "assistant") return yield* Effect.fail(new Error("Not an assistant message"))
|
||||
|
||||
const model = next.model ?? {
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
import { Effect, Schema } from "effect"
|
||||
import { SessionLegacy } from "@opencode-ai/core/session/legacy"
|
||||
import type { JSONSchema7 } from "@ai-sdk/provider"
|
||||
import type { MessageV2 } from "../session/message-v2"
|
||||
import type { Permission } from "../permission"
|
||||
@@ -38,7 +39,7 @@ export type Context<M extends Metadata = Metadata> = {
|
||||
abort: AbortSignal
|
||||
callID?: string
|
||||
extra?: { [key: string]: unknown }
|
||||
messages: MessageV2.WithParts[]
|
||||
messages: SessionLegacy.WithParts[]
|
||||
metadata(input: { title?: string; metadata?: M }): Effect.Effect<void>
|
||||
ask(input: Omit<Permission.Request, "id" | "sessionID" | "tool">): Effect.Effect<void>
|
||||
}
|
||||
@@ -47,7 +48,7 @@ export interface ExecuteResult<M extends Metadata = Metadata> {
|
||||
title: string
|
||||
metadata: M
|
||||
output: string
|
||||
attachments?: Omit<MessageV2.FilePart, "id" | "sessionID" | "messageID">[]
|
||||
attachments?: Omit<SessionLegacy.FilePart, "id" | "sessionID" | "messageID">[]
|
||||
}
|
||||
|
||||
export interface Def<
|
||||
|
||||
@@ -5,7 +5,7 @@ import * as Tool from "./tool"
|
||||
import { LSP } from "@/lsp/lsp"
|
||||
import { createTwoFilesPatch } from "diff"
|
||||
import DESCRIPTION from "./write.txt"
|
||||
import { Bus } from "../bus"
|
||||
import { EventV2Bridge } from "@/event-v2-bridge"
|
||||
import { File } from "../file"
|
||||
import { FileWatcher } from "../file/watcher"
|
||||
import { Format } from "../format"
|
||||
@@ -29,7 +29,7 @@ export const WriteTool = Tool.define(
|
||||
Effect.gen(function* () {
|
||||
const lsp = yield* LSP.Service
|
||||
const fs = yield* AppFileSystem.Service
|
||||
const bus = yield* Bus.Service
|
||||
const events = yield* EventV2Bridge.Service
|
||||
const format = yield* Format.Service
|
||||
|
||||
return {
|
||||
@@ -65,8 +65,8 @@ export const WriteTool = Tool.define(
|
||||
if (yield* format.file(filepath)) {
|
||||
yield* Bom.syncFile(fs, filepath, desiredBom)
|
||||
}
|
||||
yield* bus.publish(File.Event.Edited, { file: filepath })
|
||||
yield* bus.publish(FileWatcher.Event.Updated, {
|
||||
yield* events.publish(File.Event.Edited, { file: filepath })
|
||||
yield* events.publish(FileWatcher.Event.Updated, {
|
||||
file: filepath,
|
||||
event: exists ? "change" : "add",
|
||||
})
|
||||
|
||||
Reference in New Issue
Block a user