diff --git a/packages/core/src/plugin/host.ts b/packages/core/src/plugin/host.ts index 007a53ed70ec..8efacd15eb4c 100644 --- a/packages/core/src/plugin/host.ts +++ b/packages/core/src/plugin/host.ts @@ -378,6 +378,7 @@ export const make = Effect.fn("PluginHost.make")(function* (plugin: PluginV2.Int get: (input) => runtime.session.get(input.sessionID), prompt: runtime.session.prompt, command: runtime.session.command, + rename: runtime.session.rename, interrupt: (input) => runtime.session.interrupt(input.sessionID), }, } satisfies Plugin.Context diff --git a/packages/core/src/plugin/promise.ts b/packages/core/src/plugin/promise.ts index 75c8b300afdf..5716ddaa9a5f 100644 --- a/packages/core/src/plugin/promise.ts +++ b/packages/core/src/plugin/promise.ts @@ -70,7 +70,8 @@ export function fromPromise(plugin: Plugin) { catalog: { provider: { list: (input) => run(host.catalog.provider.list(input)), - get: (input) => run(host.catalog.provider.get({ ...input, providerID: Provider.ID.make(input.providerID) })), + get: (input) => + run(host.catalog.provider.get({ ...input, providerID: Provider.ID.make(input.providerID) })), }, model: { list: (input) => run(host.catalog.model.list(input)), @@ -96,7 +97,9 @@ export function fromPromise(plugin: Plugin) { ), connect: { key: (input) => - run(host.integration.connect.key({ ...input, integrationID: Integration.ID.make(input.integrationID) })), + run( + host.integration.connect.key({ ...input, integrationID: Integration.ID.make(input.integrationID) }), + ), oauth: (input) => run( host.integration.connect.oauth({ @@ -208,6 +211,13 @@ export function fromPromise(plugin: Plugin) { resume: input.resume ?? undefined, }), ), + rename: (input) => + run( + host.session.rename({ + ...input, + sessionID: Session.ID.make(input.sessionID), + }), + ), interrupt: (input) => run(host.session.interrupt({ sessionID: Session.ID.make(input.sessionID) })), }, } diff --git a/packages/core/src/plugin/runtime.ts b/packages/core/src/plugin/runtime.ts index e79b498bd423..0f26aa03e65a 100644 --- a/packages/core/src/plugin/runtime.ts +++ b/packages/core/src/plugin/runtime.ts @@ -11,7 +11,7 @@ import { SessionV2 } from "../session" export interface Interface { readonly session: Pick< SessionV2.Interface, - "get" | "create" | "messages" | "prompt" | "command" | "resume" | "interrupt" | "synthetic" + "get" | "create" | "messages" | "prompt" | "command" | "rename" | "resume" | "interrupt" | "synthetic" > readonly job: Pick readonly location: { @@ -51,6 +51,7 @@ export const layerWithCell = (cell: Cell) => messages: (input) => require(cell, (runtime) => runtime.session.messages(input)), prompt: (input) => require(cell, (runtime) => runtime.session.prompt(input)), command: (input) => require(cell, (runtime) => runtime.session.command(input)), + rename: (input) => require(cell, (runtime) => runtime.session.rename(input)), resume: (sessionID) => require(cell, (runtime) => runtime.session.resume(sessionID)), interrupt: (sessionID) => require(cell, (runtime) => runtime.session.interrupt(sessionID)), synthetic: (input) => require(cell, (runtime) => runtime.session.synthetic(input)), diff --git a/packages/core/test/plugin/host.ts b/packages/core/test/plugin/host.ts index 679624ee5791..19cec47a3dd0 100644 --- a/packages/core/test/plugin/host.ts +++ b/packages/core/test/plugin/host.ts @@ -82,6 +82,7 @@ export function host(overrides: Overrides = {}): PluginContext { get: () => Effect.die("unused session.get"), prompt: () => Effect.die("unused session.prompt"), command: () => Effect.die("unused session.command"), + rename: () => Effect.die("unused session.rename"), interrupt: () => Effect.die("unused session.interrupt"), }, } diff --git a/packages/core/test/plugin/promise.test.ts b/packages/core/test/plugin/promise.test.ts index 433341d39894..160b7ad8be06 100644 --- a/packages/core/test/plugin/promise.test.ts +++ b/packages/core/test/plugin/promise.test.ts @@ -4,6 +4,7 @@ import { AgentV2 } from "@opencode-ai/core/agent" import { PluginV2 } from "@opencode-ai/core/plugin" import { PluginHost } from "@opencode-ai/core/plugin/host" import { PluginPromise } from "@opencode-ai/core/plugin/promise" +import { PluginRuntime } from "@opencode-ai/core/plugin/runtime" import { SessionV2 } from "@opencode-ai/core/session" import { SessionMessage } from "@opencode-ai/core/session/message" import { ToolRegistry } from "@opencode-ai/core/tool/registry" @@ -43,6 +44,37 @@ describe("fromPromise", () => { }), ) + it.effect("forwards session rename", () => + Effect.gen(function* () { + const plugin = yield* PluginV2.Service + const runtime = yield* PluginRuntime.Service + const renamed: { sessionID: SessionV2.ID; title: string }[] = [] + const host = yield* PluginHost.make(plugin).pipe( + Effect.provideService( + PluginRuntime.Service, + PluginRuntime.Service.of({ + ...runtime, + session: { + ...runtime.session, + rename: (input) => + Effect.sync(() => { + renamed.push(input) + }), + }, + }), + ), + ) + const promisePlugin = Plugin.define({ + id: "promise-session-rename", + setup: (ctx) => ctx.session.rename({ sessionID: "ses_plugin_rename", title: "Updated scope" }), + }) + + yield* PluginPromise.fromPromise(promisePlugin).effect(host) + + expect(renamed).toEqual([{ sessionID: SessionV2.ID.make("ses_plugin_rename"), title: "Updated scope" }]) + }), + ) + it.effect("loads a promise plugin and registers a transform hook", () => Effect.gen(function* () { const agents = yield* AgentV2.Service diff --git a/packages/docs/build/plugins.mdx b/packages/docs/build/plugins.mdx index 08c8ce4decad..ea079fede16d 100644 --- a/packages/docs/build/plugins.mdx +++ b/packages/docs/build/plugins.mdx @@ -177,7 +177,7 @@ and plugin options. | `ctx.integration` | `list`, `get`, `connect`, `attempt`, `transform`, `reload`, and connection lookup/resolution | | `ctx.plugin` | `list` currently active plugin IDs | | `ctx.reference` | `list`, `transform`, `reload` | -| `ctx.session` | `create`, `get`, `prompt`, `command`, `interrupt`, and `hook` | +| `ctx.session` | `create`, `get`, `prompt`, `command`, `rename`, `interrupt`, and `hook` | | `ctx.skill` | `list`, `transform`, `reload` | | `ctx.tool` | `transform` and `hook` | | `ctx.aisdk` | `hook` | diff --git a/packages/plugin/src/v2/effect/session.ts b/packages/plugin/src/v2/effect/session.ts index 40da735cbea8..62943885a5ef 100644 --- a/packages/plugin/src/v2/effect/session.ts +++ b/packages/plugin/src/v2/effect/session.ts @@ -1,3 +1,3 @@ import type { SessionApi } from "@opencode-ai/client/effect/api" -export type SessionDomain = Pick, "create" | "get" | "prompt" | "command" | "interrupt"> +export type SessionDomain = Pick, "create" | "get" | "prompt" | "command" | "rename" | "interrupt"> diff --git a/packages/plugin/src/v2/promise/session.ts b/packages/plugin/src/v2/promise/session.ts index c521c8fddd6f..d33b77322b5b 100644 --- a/packages/plugin/src/v2/promise/session.ts +++ b/packages/plugin/src/v2/promise/session.ts @@ -1,3 +1,3 @@ import type { SessionApi } from "@opencode-ai/client/promise/api" -export type SessionDomain = Pick +export type SessionDomain = Pick