feat(plugin): add session request hook (#35794)
This commit is contained in:
parent
e25a724bc2
commit
4f976bcf1a
124 changed files with 7743 additions and 5620 deletions
|
|
@ -1,6 +1,6 @@
|
|||
export * as ApplyPatchTool from "./apply-patch"
|
||||
|
||||
import type { PluginContext } from "@opencode-ai/plugin/v2/effect"
|
||||
import type { Context as PluginContext } from "@opencode-ai/plugin/v2/effect/plugin"
|
||||
import { ToolFailure } from "@opencode-ai/llm"
|
||||
import { FileDiff } from "@opencode-ai/schema/file-diff"
|
||||
import { createTwoFilesPatch, diffLines } from "diff"
|
||||
|
|
@ -194,6 +194,19 @@ export const Plugin = {
|
|||
),
|
||||
)
|
||||
.pipe(Effect.orDie)
|
||||
|
||||
yield* ctx.session.hook("request", (event) =>
|
||||
Effect.sync(() => {
|
||||
const usePatch =
|
||||
event.model.providerID.toLowerCase() === "openai" || event.model.id.toLowerCase().includes("gpt")
|
||||
if (usePatch) {
|
||||
delete event.tools.edit
|
||||
delete event.tools.write
|
||||
return
|
||||
}
|
||||
delete event.tools.patch
|
||||
}),
|
||||
)
|
||||
}),
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -6,7 +6,7 @@
|
|||
*/
|
||||
export * as EditTool from "./edit"
|
||||
|
||||
import type { PluginContext } from "@opencode-ai/plugin/v2/effect"
|
||||
import type { Context as PluginContext } from "@opencode-ai/plugin/v2/effect/plugin"
|
||||
import { ToolFailure } from "@opencode-ai/llm"
|
||||
import { FileDiff } from "@opencode-ai/schema/file-diff"
|
||||
import { createTwoFilesPatch, diffLines } from "diff"
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
export * as GlobTool from "./glob"
|
||||
|
||||
import { ToolFailure } from "@opencode-ai/llm"
|
||||
import type { PluginContext } from "@opencode-ai/plugin/v2/effect"
|
||||
import type { Context as PluginContext } from "@opencode-ai/plugin/v2/effect/plugin"
|
||||
import { Effect, Schema } from "effect"
|
||||
import path from "path"
|
||||
import { FileSystem } from "../filesystem"
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
export * as GrepTool from "./grep"
|
||||
|
||||
import type { PluginContext } from "@opencode-ai/plugin/v2/effect"
|
||||
import type { Context as PluginContext } from "@opencode-ai/plugin/v2/effect/plugin"
|
||||
import { ToolFailure } from "@opencode-ai/llm"
|
||||
import { Effect, Schema } from "effect"
|
||||
import path from "path"
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
export * as QuestionTool from "./question"
|
||||
|
||||
import type { PluginContext } from "@opencode-ai/plugin/v2/effect"
|
||||
import type { Context as PluginContext } from "@opencode-ai/plugin/v2/effect/plugin"
|
||||
import { ToolFailure } from "@opencode-ai/llm"
|
||||
import { Effect, Schema } from "effect"
|
||||
import { Form } from "../form"
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
export * as ReadTool from "./read"
|
||||
|
||||
import type { PluginContext } from "@opencode-ai/plugin/v2/effect"
|
||||
import type { Context as PluginContext } from "@opencode-ai/plugin/v2/effect/plugin"
|
||||
import { dirname } from "path"
|
||||
import { ToolFailure } from "@opencode-ai/llm"
|
||||
import { Effect, Schema } from "effect"
|
||||
|
|
|
|||
|
|
@ -191,12 +191,8 @@ const registryLayer = Layer.effect(
|
|||
const registration = entries.at(-1)?.registration
|
||||
if (registration) registrations.set(name, registration)
|
||||
}
|
||||
// OpenAI/GPT models use patch; every other model uses edit and write.
|
||||
const usePatch = input.model.provider.toLowerCase() === "openai" || input.model.id.toLowerCase().includes("gpt")
|
||||
for (const [name, registration] of registrations) {
|
||||
const wrongEditTool = name === "patch" ? !usePatch : (name === "edit" || name === "write") && usePatch
|
||||
if (
|
||||
wrongEditTool ||
|
||||
(registration.deferred && !Flag.CODEMODE_ENABLED) ||
|
||||
whollyDisabled(permission(registration.tool, name), input.permissions ?? [])
|
||||
)
|
||||
|
|
|
|||
|
|
@ -2,7 +2,7 @@ export * as ShellTool from "./shell"
|
|||
|
||||
import path from "path"
|
||||
import { ToolFailure } from "@opencode-ai/llm"
|
||||
import type { PluginContext } from "@opencode-ai/plugin/v2/effect"
|
||||
import type { Context as PluginContext } from "@opencode-ai/plugin/v2/effect/plugin"
|
||||
import { Effect, Schema, Scope } from "effect"
|
||||
import { FSUtil } from "../fs-util"
|
||||
import { LocationMutation } from "../location-mutation"
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
export * as SkillTool from "./skill"
|
||||
|
||||
import type { PluginContext } from "@opencode-ai/plugin/v2/effect"
|
||||
import type { Context as PluginContext } from "@opencode-ai/plugin/v2/effect/plugin"
|
||||
import path from "path"
|
||||
import { ToolFailure } from "@opencode-ai/llm"
|
||||
import { Effect, Schema } from "effect"
|
||||
|
|
|
|||
|
|
@ -1,10 +1,11 @@
|
|||
export * as SubagentTool from "./subagent"
|
||||
|
||||
import { ToolFailure } from "@opencode-ai/llm"
|
||||
import type { PluginContext } from "@opencode-ai/plugin/v2/effect"
|
||||
import type { Context as PluginContext } from "@opencode-ai/plugin/v2/effect/plugin"
|
||||
import { Effect, Schema, Scope } from "effect"
|
||||
import { AgentV2 } from "../agent"
|
||||
import { PluginRuntime } from "../plugin/runtime"
|
||||
import { PermissionV2 } from "../permission"
|
||||
import { SessionSchema } from "../session/schema"
|
||||
import { Tool } from "./tool"
|
||||
|
||||
|
|
@ -42,6 +43,7 @@ export const Plugin = {
|
|||
effect: Effect.fn("SubagentTool.Plugin")(function* (ctx: PluginContext) {
|
||||
const runtime = yield* PluginRuntime.Service
|
||||
const agents = yield* AgentV2.Service
|
||||
const permission = yield* PermissionV2.Service
|
||||
const scope = yield* Scope.Scope
|
||||
|
||||
// Concatenate the child's final completed assistant text. Distinguishes "completed with no
|
||||
|
|
@ -114,6 +116,20 @@ export const Plugin = {
|
|||
if (agent === undefined) return yield* new ToolFailure({ message: `Unknown agent: ${input.agent}` })
|
||||
if (agent.mode === "primary")
|
||||
return yield* new ToolFailure({ message: `Agent ${input.agent} cannot run as a subagent` })
|
||||
yield* permission
|
||||
.assert({
|
||||
action: name,
|
||||
resources: [agent.id],
|
||||
save: [agent.id],
|
||||
sessionID: context.sessionID,
|
||||
agent: context.agent,
|
||||
source: {
|
||||
type: "tool",
|
||||
messageID: context.assistantMessageID,
|
||||
callID: context.toolCallID,
|
||||
},
|
||||
})
|
||||
.pipe(Effect.mapError((error) => new ToolFailure({ message: `Subagent denied: ${agent.id}`, error })))
|
||||
|
||||
// Model selection is policy/config/session state, not an LLM-facing tool argument.
|
||||
const model = agent.model ?? parent.model
|
||||
|
|
@ -176,5 +192,32 @@ export const Plugin = {
|
|||
),
|
||||
)
|
||||
.pipe(Effect.orDie)
|
||||
|
||||
yield* ctx.session.hook("request", (event) =>
|
||||
Effect.gen(function* () {
|
||||
const tool = event.tools[name]
|
||||
if (!tool) return
|
||||
const selected = yield* agents.resolve(event.agent)
|
||||
if (!selected) return
|
||||
const available = (yield* agents.list())
|
||||
.filter(
|
||||
(agent) =>
|
||||
agent.mode !== "primary" &&
|
||||
!agent.hidden &&
|
||||
PermissionV2.evaluate(name, agent.id, selected.permissions).effect !== "deny",
|
||||
)
|
||||
.toSorted((a, b) => a.id.localeCompare(b.id))
|
||||
if (available.length === 0) return
|
||||
tool.description = [
|
||||
tool.description,
|
||||
"",
|
||||
"Available subagents:",
|
||||
...available.map(
|
||||
(agent) =>
|
||||
`- ${agent.id}: ${agent.description ?? "This subagent should only be called when explicitly requested."}`,
|
||||
),
|
||||
].join("\n")
|
||||
}),
|
||||
)
|
||||
}),
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
export * as TodoWriteTool from "./todowrite"
|
||||
|
||||
import type { PluginContext } from "@opencode-ai/plugin/v2/effect"
|
||||
import type { Context as PluginContext } from "@opencode-ai/plugin/v2/effect/plugin"
|
||||
import { ToolFailure } from "@opencode-ai/llm"
|
||||
import { Effect, Schema } from "effect"
|
||||
import { PermissionV2 } from "../permission"
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
export * as WebFetchTool from "./webfetch"
|
||||
|
||||
import type { PluginContext } from "@opencode-ai/plugin/v2/effect"
|
||||
import type { Context as PluginContext } from "@opencode-ai/plugin/v2/effect/plugin"
|
||||
import { ToolFailure } from "@opencode-ai/llm"
|
||||
import { Duration, Effect, Schema } from "effect"
|
||||
import { HttpClient, HttpClientRequest, HttpClientResponse } from "effect/unstable/http"
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
export * as WebSearchTool from "./websearch"
|
||||
|
||||
import type { PluginContext } from "@opencode-ai/plugin/v2/effect"
|
||||
import type { Context as PluginContext } from "@opencode-ai/plugin/v2/effect/plugin"
|
||||
import { ToolFailure } from "@opencode-ai/llm"
|
||||
import { Context, Duration, Effect, Layer, Schema } from "effect"
|
||||
import { HttpClient, HttpClientRequest } from "effect/unstable/http"
|
||||
|
|
|
|||
|
|
@ -6,7 +6,7 @@
|
|||
*/
|
||||
export * as WriteTool from "./write"
|
||||
|
||||
import type { PluginContext } from "@opencode-ai/plugin/v2/effect"
|
||||
import type { Context as PluginContext } from "@opencode-ai/plugin/v2/effect/plugin"
|
||||
import { ToolFailure } from "@opencode-ai/llm"
|
||||
import { Effect, Schema } from "effect"
|
||||
import { FileMutation } from "../file-mutation"
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue