fix(plugin): adapt promise host wire values
This commit is contained in:
parent
b87bb4486f
commit
20e37e7122
3 changed files with 137 additions and 19 deletions
|
|
@ -193,12 +193,12 @@ import { ClientError } from "./client-error"
|
|||
export interface ClientOptions {
|
||||
readonly baseUrl: string
|
||||
readonly fetch?: typeof globalThis.fetch
|
||||
readonly headers?: HeadersInit
|
||||
readonly headers?: RequestInit["headers"]
|
||||
}
|
||||
|
||||
export interface RequestOptions {
|
||||
readonly signal?: AbortSignal
|
||||
readonly headers?: HeadersInit
|
||||
readonly headers?: RequestInit["headers"]
|
||||
}
|
||||
|
||||
interface RequestDescriptor {
|
||||
|
|
|
|||
|
|
@ -2,13 +2,26 @@ export * as PluginPromise from "./promise"
|
|||
|
||||
import { Plugin } from "@opencode-ai/plugin/v2/effect"
|
||||
import type { AnyTool } from "@opencode-ai/plugin/v2/tool"
|
||||
import { Effect, Scope, Stream } from "effect"
|
||||
import { Agent } from "@opencode-ai/schema/agent"
|
||||
import { Integration } from "@opencode-ai/schema/integration"
|
||||
import { Location } from "@opencode-ai/schema/location"
|
||||
import { Model } from "@opencode-ai/schema/model"
|
||||
import { Provider } from "@opencode-ai/schema/provider"
|
||||
import { AbsolutePath } from "@opencode-ai/schema/schema"
|
||||
import { Session } from "@opencode-ai/schema/session"
|
||||
import { SessionMessage } from "@opencode-ai/schema/session-message"
|
||||
import { Workspace } from "@opencode-ai/schema/workspace"
|
||||
import { DateTime, Effect, Scope, Stream } from "effect"
|
||||
import { Tool } from "../tool/tool"
|
||||
|
||||
type HostRegistration = { readonly dispose: Effect.Effect<void> }
|
||||
type Registration = { readonly dispose: () => Promise<void> }
|
||||
type PromisePlugin = import("@opencode-ai/plugin/v2/plugin").Plugin
|
||||
type PromisePluginContext = import("@opencode-ai/plugin/v2/plugin").Context
|
||||
type PromiseEvent = ReturnType<PromisePluginContext["event"]["subscribe"]> extends AsyncIterable<infer Event>
|
||||
? Event
|
||||
: never
|
||||
type JsonValue = null | boolean | number | string | Array<JsonValue> | { [key: string]: JsonValue }
|
||||
|
||||
/**
|
||||
* Adapts a Promise plugin into an Effect plugin so the existing Effect-only
|
||||
|
|
@ -33,7 +46,7 @@ export function fromPromise(plugin: PromisePlugin) {
|
|||
dispose: () => Effect.runPromiseWith(context)(registration.dispose),
|
||||
}))
|
||||
|
||||
const run = <A, E>(effect: Effect.Effect<A, E>) => Effect.runPromiseWith(context)(effect)
|
||||
const run = <A, E>(effect: Effect.Effect<A, E>) => Effect.runPromiseWith(context)(effect).then(wire)
|
||||
|
||||
const transform =
|
||||
<Draft>(domain: {
|
||||
|
|
@ -60,11 +73,12 @@ export function fromPromise(plugin: PromisePlugin) {
|
|||
catalog: {
|
||||
provider: {
|
||||
list: (input) => run(host.catalog.provider.list(input)),
|
||||
get: (input) => run(host.catalog.provider.get(input)),
|
||||
get: (input) => run(host.catalog.provider.get({ ...input, providerID: Provider.ID.make(input.providerID) })),
|
||||
},
|
||||
model: {
|
||||
list: (input) => run(host.catalog.model.list(input)),
|
||||
default: (input) => run(host.catalog.model.default(input)),
|
||||
default: (input) =>
|
||||
run(host.catalog.model.default(input)).then((result) => ({ ...result, data: result.data ?? null })),
|
||||
},
|
||||
transform: transform(host.catalog),
|
||||
reload: () => run(host.catalog.reload()),
|
||||
|
|
@ -75,19 +89,48 @@ export function fromPromise(plugin: PromisePlugin) {
|
|||
reload: () => run(host.command.reload()),
|
||||
},
|
||||
event: {
|
||||
subscribe: () => Stream.toAsyncIterable(host.event.subscribe()),
|
||||
subscribe: () => Stream.toAsyncIterable(host.event.subscribe().pipe(Stream.map(wireEvent))),
|
||||
},
|
||||
integration: {
|
||||
list: (input) => run(host.integration.list(input)),
|
||||
get: (input) => run(host.integration.get(input)),
|
||||
get: (input) =>
|
||||
run(host.integration.get({ ...input, integrationID: Integration.ID.make(input.integrationID) })).then(
|
||||
(result) => ({ ...result, data: result.data ?? null }),
|
||||
),
|
||||
connect: {
|
||||
key: (input) => run(host.integration.connect.key(input)),
|
||||
oauth: (input) => run(host.integration.connect.oauth(input)),
|
||||
key: (input) =>
|
||||
run(host.integration.connect.key({ ...input, integrationID: Integration.ID.make(input.integrationID) })),
|
||||
oauth: (input) =>
|
||||
run(
|
||||
host.integration.connect.oauth({
|
||||
...input,
|
||||
integrationID: Integration.ID.make(input.integrationID),
|
||||
methodID: Integration.MethodID.make(input.methodID),
|
||||
}),
|
||||
),
|
||||
},
|
||||
attempt: {
|
||||
status: (input) => run(host.integration.attempt.status(input)),
|
||||
complete: (input) => run(host.integration.attempt.complete(input)),
|
||||
cancel: (input) => run(host.integration.attempt.cancel(input)),
|
||||
status: (input) =>
|
||||
run(
|
||||
host.integration.attempt.status({
|
||||
...input,
|
||||
attemptID: Integration.AttemptID.make(input.attemptID),
|
||||
}),
|
||||
),
|
||||
complete: (input) =>
|
||||
run(
|
||||
host.integration.attempt.complete({
|
||||
...input,
|
||||
attemptID: Integration.AttemptID.make(input.attemptID),
|
||||
}),
|
||||
),
|
||||
cancel: (input) =>
|
||||
run(
|
||||
host.integration.attempt.cancel({
|
||||
...input,
|
||||
attemptID: Integration.AttemptID.make(input.attemptID),
|
||||
}),
|
||||
),
|
||||
},
|
||||
transform: transform(host.integration),
|
||||
reload: () => run(host.integration.reload()),
|
||||
|
|
@ -122,11 +165,53 @@ export function fromPromise(plugin: PromisePlugin) {
|
|||
register(host.tool.hook(name, (event) => Effect.promise(() => Promise.resolve(callback(event))))),
|
||||
},
|
||||
session: {
|
||||
create: (input) => run(host.session.create(input)),
|
||||
get: (input) => run(host.session.get(input)),
|
||||
prompt: (input) => run(host.session.prompt(input)),
|
||||
command: (input) => run(host.session.command(input)),
|
||||
interrupt: (input) => run(host.session.interrupt(input)),
|
||||
create: (input) =>
|
||||
run(
|
||||
host.session.create(
|
||||
input === undefined
|
||||
? undefined
|
||||
: {
|
||||
id: input.id == null ? undefined : Session.ID.make(input.id),
|
||||
agent: input.agent == null ? undefined : Agent.ID.make(input.agent),
|
||||
model: input.model == null ? undefined : model(input.model),
|
||||
location:
|
||||
input.location == null
|
||||
? undefined
|
||||
: Location.Ref.make({
|
||||
directory: AbsolutePath.make(input.location.directory),
|
||||
workspaceID:
|
||||
input.location.workspaceID === undefined
|
||||
? undefined
|
||||
: Workspace.ID.make(input.location.workspaceID),
|
||||
}),
|
||||
},
|
||||
),
|
||||
),
|
||||
get: (input) => run(host.session.get({ sessionID: Session.ID.make(input.sessionID) })),
|
||||
prompt: (input) =>
|
||||
run(
|
||||
host.session.prompt({
|
||||
...input,
|
||||
sessionID: Session.ID.make(input.sessionID),
|
||||
id: input.id == null ? undefined : SessionMessage.ID.make(input.id),
|
||||
delivery: input.delivery ?? undefined,
|
||||
resume: input.resume ?? undefined,
|
||||
}),
|
||||
),
|
||||
command: (input) =>
|
||||
run(
|
||||
host.session.command({
|
||||
...input,
|
||||
sessionID: Session.ID.make(input.sessionID),
|
||||
id: input.id == null ? undefined : SessionMessage.ID.make(input.id),
|
||||
agent: input.agent == null ? undefined : Agent.ID.make(input.agent),
|
||||
model: input.model == null ? undefined : model(input.model),
|
||||
arguments: input.arguments ?? undefined,
|
||||
delivery: input.delivery ?? undefined,
|
||||
resume: input.resume ?? undefined,
|
||||
}),
|
||||
),
|
||||
interrupt: (input) => run(host.session.interrupt({ sessionID: Session.ID.make(input.sessionID) })),
|
||||
},
|
||||
}
|
||||
|
||||
|
|
@ -137,6 +222,39 @@ export function fromPromise(plugin: PromisePlugin) {
|
|||
})
|
||||
}
|
||||
|
||||
function model(input: { readonly id: string; readonly providerID: string; readonly variant?: string }) {
|
||||
return Model.Ref.make({
|
||||
id: Model.ID.make(input.id),
|
||||
providerID: Provider.ID.make(input.providerID),
|
||||
variant: input.variant === undefined ? undefined : Model.VariantID.make(input.variant),
|
||||
})
|
||||
}
|
||||
|
||||
type Wire<Value> = unknown extends Value
|
||||
? JsonValue
|
||||
: Value extends string | number | boolean | bigint | symbol | null | undefined
|
||||
? Value
|
||||
: Value extends DateTime.DateTime
|
||||
? number
|
||||
: Value extends ReadonlyArray<infer Item>
|
||||
? Array<Wire<Item>>
|
||||
: Value extends object
|
||||
? { -readonly [Key in keyof Value]: Wire<Value[Key]> }
|
||||
: Value
|
||||
|
||||
function wire<Value>(value: Value): Wire<Value>
|
||||
function wire(value: unknown): unknown {
|
||||
if (DateTime.isDateTime(value)) return DateTime.toEpochMillis(value)
|
||||
if (Array.isArray(value)) return value.map(wire)
|
||||
if (typeof value !== "object" || value === null) return value
|
||||
return Object.fromEntries(Object.entries(value).map(([key, item]) => [key, wire(item)]))
|
||||
}
|
||||
|
||||
function wireEvent(value: unknown): PromiseEvent
|
||||
function wireEvent(value: unknown): unknown {
|
||||
return wire(value)
|
||||
}
|
||||
|
||||
function fromPromiseTool(tool: AnyTool) {
|
||||
if ("jsonSchema" in tool)
|
||||
return Tool.make({
|
||||
|
|
|
|||
File diff suppressed because one or more lines are too long
Loading…
Add table
Add a link
Reference in a new issue