feat(plugin): expose synthetic session input (#37212)
This commit is contained in:
@@ -425,6 +425,7 @@ export const make = Effect.fn("PluginHost.make")(function* (plugin: PluginV2.Int
|
|||||||
get: (input) => runtime.session.get(input.sessionID),
|
get: (input) => runtime.session.get(input.sessionID),
|
||||||
prompt: runtime.session.prompt,
|
prompt: runtime.session.prompt,
|
||||||
command: runtime.session.command,
|
command: runtime.session.command,
|
||||||
|
synthetic: runtime.session.synthetic,
|
||||||
interrupt: (input) => runtime.session.interrupt(input.sessionID),
|
interrupt: (input) => runtime.session.interrupt(input.sessionID),
|
||||||
},
|
},
|
||||||
} satisfies Plugin.Context
|
} satisfies Plugin.Context
|
||||||
|
|||||||
@@ -244,6 +244,17 @@ export function fromPromise(plugin: Plugin) {
|
|||||||
resume: input.resume ?? undefined,
|
resume: input.resume ?? undefined,
|
||||||
}),
|
}),
|
||||||
),
|
),
|
||||||
|
synthetic: (input) =>
|
||||||
|
run(
|
||||||
|
host.session.synthetic({
|
||||||
|
...input,
|
||||||
|
sessionID: Session.ID.make(input.sessionID),
|
||||||
|
id: input.id == null ? undefined : SessionMessage.ID.make(input.id),
|
||||||
|
description: input.description ?? undefined,
|
||||||
|
delivery: input.delivery ?? undefined,
|
||||||
|
resume: input.resume ?? undefined,
|
||||||
|
}),
|
||||||
|
),
|
||||||
interrupt: (input) => run(host.session.interrupt({ sessionID: Session.ID.make(input.sessionID) })),
|
interrupt: (input) => run(host.session.interrupt({ sessionID: Session.ID.make(input.sessionID) })),
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -97,6 +97,7 @@ export function host(overrides: Overrides = {}): PluginContext {
|
|||||||
get: overrides.session?.get ?? (() => Effect.die("unused session.get")),
|
get: overrides.session?.get ?? (() => Effect.die("unused session.get")),
|
||||||
prompt: overrides.session?.prompt ?? (() => Effect.die("unused session.prompt")),
|
prompt: overrides.session?.prompt ?? (() => Effect.die("unused session.prompt")),
|
||||||
command: overrides.session?.command ?? (() => Effect.die("unused session.command")),
|
command: overrides.session?.command ?? (() => Effect.die("unused session.command")),
|
||||||
|
synthetic: overrides.session?.synthetic ?? (() => Effect.die("unused session.synthetic")),
|
||||||
interrupt: overrides.session?.interrupt ?? (() => Effect.die("unused session.interrupt")),
|
interrupt: overrides.session?.interrupt ?? (() => Effect.die("unused session.interrupt")),
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
import { describe, expect } from "bun:test"
|
import { describe, expect } from "bun:test"
|
||||||
import { Message, SystemPart } from "@opencode-ai/ai"
|
import { Message, SystemPart } from "@opencode-ai/ai"
|
||||||
import { Effect, Schema } from "effect"
|
import { DateTime, Effect, Schema } from "effect"
|
||||||
import { AgentV2 } from "@opencode-ai/core/agent"
|
import { AgentV2 } from "@opencode-ai/core/agent"
|
||||||
import { Catalog } from "@opencode-ai/core/catalog"
|
import { Catalog } from "@opencode-ai/core/catalog"
|
||||||
import { ModelV2 } from "@opencode-ai/core/model"
|
import { ModelV2 } from "@opencode-ai/core/model"
|
||||||
@@ -10,6 +10,7 @@ import { PluginHost } from "@opencode-ai/core/plugin/host"
|
|||||||
import { PluginPromise } from "@opencode-ai/core/plugin/promise"
|
import { PluginPromise } from "@opencode-ai/core/plugin/promise"
|
||||||
import { SessionV2 } from "@opencode-ai/core/session"
|
import { SessionV2 } from "@opencode-ai/core/session"
|
||||||
import { SessionMessage } from "@opencode-ai/core/session/message"
|
import { SessionMessage } from "@opencode-ai/core/session/message"
|
||||||
|
import { SessionPending } from "@opencode-ai/core/session/pending"
|
||||||
import { ToolRegistry } from "@opencode-ai/core/tool/registry"
|
import { ToolRegistry } from "@opencode-ai/core/tool/registry"
|
||||||
import { ProviderV2 } from "@opencode-ai/core/provider"
|
import { ProviderV2 } from "@opencode-ai/core/provider"
|
||||||
import { Plugin } from "@opencode-ai/plugin/v2"
|
import { Plugin } from "@opencode-ai/plugin/v2"
|
||||||
@@ -18,10 +19,63 @@ import { Model } from "@opencode-ai/schema/model"
|
|||||||
import { Provider } from "@opencode-ai/schema/provider"
|
import { Provider } from "@opencode-ai/schema/provider"
|
||||||
import { testEffect } from "../lib/effect"
|
import { testEffect } from "../lib/effect"
|
||||||
import { PluginTestLayer } from "./fixture"
|
import { PluginTestLayer } from "./fixture"
|
||||||
|
import { host as testHost } from "./host"
|
||||||
|
|
||||||
const it = testEffect(PluginTestLayer)
|
const it = testEffect(PluginTestLayer)
|
||||||
|
|
||||||
describe("fromPromise", () => {
|
describe("fromPromise", () => {
|
||||||
|
it.effect("forwards synthetic session input", () =>
|
||||||
|
Effect.gen(function* () {
|
||||||
|
const input = {
|
||||||
|
sessionID: "ses_synthetic",
|
||||||
|
id: "msg_synthetic",
|
||||||
|
text: "Background work completed",
|
||||||
|
description: null,
|
||||||
|
metadata: { shellID: "shell_1" },
|
||||||
|
delivery: null,
|
||||||
|
resume: null,
|
||||||
|
}
|
||||||
|
let seen: unknown
|
||||||
|
const host = testHost({
|
||||||
|
session: {
|
||||||
|
synthetic: (value) => {
|
||||||
|
seen = value
|
||||||
|
return Effect.succeed(
|
||||||
|
SessionPending.Synthetic.make({
|
||||||
|
admittedSeq: 1,
|
||||||
|
id: SessionMessage.ID.make(input.id),
|
||||||
|
sessionID: SessionV2.ID.make(input.sessionID),
|
||||||
|
timeCreated: DateTime.makeUnsafe(0),
|
||||||
|
type: "synthetic",
|
||||||
|
data: {
|
||||||
|
text: input.text,
|
||||||
|
metadata: input.metadata,
|
||||||
|
},
|
||||||
|
delivery: "queue",
|
||||||
|
}),
|
||||||
|
)
|
||||||
|
},
|
||||||
|
},
|
||||||
|
})
|
||||||
|
|
||||||
|
yield* PluginPromise.fromPromise(
|
||||||
|
Plugin.define({
|
||||||
|
id: "promise-session-synthetic",
|
||||||
|
setup: async (ctx) => {
|
||||||
|
await ctx.session.synthetic(input)
|
||||||
|
},
|
||||||
|
}),
|
||||||
|
).effect(host)
|
||||||
|
|
||||||
|
expect(seen).toEqual({
|
||||||
|
...input,
|
||||||
|
description: undefined,
|
||||||
|
delivery: undefined,
|
||||||
|
resume: undefined,
|
||||||
|
})
|
||||||
|
}),
|
||||||
|
)
|
||||||
|
|
||||||
it.effect("forwards standard client reads", () =>
|
it.effect("forwards standard client reads", () =>
|
||||||
Effect.gen(function* () {
|
Effect.gen(function* () {
|
||||||
const plugin = yield* PluginV2.Service
|
const plugin = yield* PluginV2.Service
|
||||||
|
|||||||
Vendored
+1
-1
@@ -177,7 +177,7 @@ and plugin options.
|
|||||||
| `ctx.integration` | `list`, `get`, `connect`, `attempt`, `transform`, `reload`, and connection lookup/resolution |
|
| `ctx.integration` | `list`, `get`, `connect`, `attempt`, `transform`, `reload`, and connection lookup/resolution |
|
||||||
| `ctx.plugin` | `list` currently active plugin IDs |
|
| `ctx.plugin` | `list` currently active plugin IDs |
|
||||||
| `ctx.reference` | `list`, `transform`, `reload` |
|
| `ctx.reference` | `list`, `transform`, `reload` |
|
||||||
| `ctx.session` | `create`, `get`, `prompt`, `command`, `interrupt`, and `hook` |
|
| `ctx.session` | `create`, `get`, `prompt`, `command`, `synthetic`, `interrupt`, and `hook` |
|
||||||
| `ctx.skill` | `list`, `transform`, `reload` |
|
| `ctx.skill` | `list`, `transform`, `reload` |
|
||||||
| `ctx.tool` | `transform` and `hook` |
|
| `ctx.tool` | `transform` and `hook` |
|
||||||
| `ctx.aisdk` | `hook` |
|
| `ctx.aisdk` | `hook` |
|
||||||
|
|||||||
@@ -19,6 +19,9 @@ export interface SessionHooks {
|
|||||||
readonly context: SessionContext
|
readonly context: SessionContext
|
||||||
}
|
}
|
||||||
|
|
||||||
export type SessionDomain = Pick<SessionApi<unknown>, "create" | "get" | "prompt" | "command" | "interrupt"> & {
|
export type SessionDomain = Pick<
|
||||||
|
SessionApi<unknown>,
|
||||||
|
"create" | "get" | "prompt" | "command" | "synthetic" | "interrupt"
|
||||||
|
> & {
|
||||||
readonly hook: Hooks<SessionHooks>
|
readonly hook: Hooks<SessionHooks>
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -19,6 +19,6 @@ export interface SessionHooks {
|
|||||||
readonly context: SessionContext
|
readonly context: SessionContext
|
||||||
}
|
}
|
||||||
|
|
||||||
export type SessionDomain = Pick<SessionApi, "create" | "get" | "prompt" | "command" | "interrupt"> & {
|
export type SessionDomain = Pick<SessionApi, "create" | "get" | "prompt" | "command" | "synthetic" | "interrupt"> & {
|
||||||
readonly hook: Hooks<SessionHooks>
|
readonly hook: Hooks<SessionHooks>
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user