feat(plugin): expose session list and messages with cursor pagination
This commit is contained in:
parent
903acdf0d4
commit
3cac6d60ed
5 changed files with 45 additions and 3 deletions
|
|
@ -4,6 +4,8 @@ import { Plugin } from "@opencode-ai/plugin/effect"
|
|||
import type { IntegrationMethodRegistration } from "@opencode-ai/plugin/effect/integration"
|
||||
import type { CredentialOAuth } from "@opencode-ai/sdk/v2/types"
|
||||
import { EventManifest } from "@opencode-ai/schema/event-manifest"
|
||||
import { SessionMessagesCursor } from "@opencode-ai/schema/session-messages-cursor"
|
||||
import { SessionsQuery } from "@opencode-ai/schema/sessions-query"
|
||||
import { App } from "../app"
|
||||
import { Effect, Schema, Stream } from "effect"
|
||||
import { Agent } from "../agent"
|
||||
|
|
@ -348,6 +350,40 @@ export const make = Effect.fn("PluginHost.make")(function* (plugin: import("../p
|
|||
input?.location ?? Location.Ref.make({ directory: location.directory, workspaceID: location.workspaceID }),
|
||||
}),
|
||||
get: (input) => runtime.session.get(input.sessionID),
|
||||
list: (input) =>
|
||||
Effect.gen(function* () {
|
||||
const query =
|
||||
input?.cursor !== undefined
|
||||
? yield* SessionsQuery.Cursor.parse(input.cursor).pipe(
|
||||
Effect.mapError(() => new Error("Invalid cursor")),
|
||||
)
|
||||
: (input ?? {})
|
||||
const page = yield* runtime.session.list({
|
||||
...query,
|
||||
workspaceID: query.workspace,
|
||||
limit: input?.limit ?? SessionsQuery.DefaultLimit,
|
||||
})
|
||||
return { data: page.data, cursor: SessionsQuery.Cursor.page(query, page.data) }
|
||||
}),
|
||||
messages: (input) =>
|
||||
Effect.gen(function* () {
|
||||
if (input.cursor !== undefined && input.order !== undefined)
|
||||
return yield* Effect.fail(new Error("Cursor cannot be combined with order"))
|
||||
const decoded =
|
||||
input.cursor !== undefined
|
||||
? yield* SessionMessagesCursor.parse(input.cursor).pipe(
|
||||
Effect.mapError(() => new Error("Invalid cursor")),
|
||||
)
|
||||
: undefined
|
||||
const order = decoded?.order ?? input.order ?? "desc"
|
||||
const data = yield* runtime.session.messages({
|
||||
sessionID: input.sessionID,
|
||||
limit: input.limit ?? SessionMessagesCursor.DefaultLimit,
|
||||
order,
|
||||
cursor: decoded ? { id: decoded.id, direction: decoded.direction } : undefined,
|
||||
})
|
||||
return { data, cursor: SessionMessagesCursor.page(data, order) }
|
||||
}),
|
||||
prompt: runtime.session.prompt,
|
||||
generate: (input) => runtime.session.generate(input).pipe(Effect.map((text) => ({ text }))),
|
||||
command: runtime.session.command,
|
||||
|
|
|
|||
|
|
@ -13,6 +13,7 @@ export interface Interface {
|
|||
Session.Interface,
|
||||
| "get"
|
||||
| "create"
|
||||
| "list"
|
||||
| "messages"
|
||||
| "prompt"
|
||||
| "generate"
|
||||
|
|
@ -58,6 +59,7 @@ export const layerWithCell = (cell: Cell) =>
|
|||
session: {
|
||||
get: (sessionID) => require(cell, (runtime) => runtime.session.get(sessionID)),
|
||||
create: (input) => require(cell, (runtime) => runtime.session.create(input)),
|
||||
list: (input) => require(cell, (runtime) => runtime.session.list(input)),
|
||||
messages: (input) => require(cell, (runtime) => runtime.session.messages(input)),
|
||||
prompt: (input) => require(cell, (runtime) => runtime.session.prompt(input)),
|
||||
generate: (input) => require(cell, (runtime) => runtime.session.generate(input)),
|
||||
|
|
|
|||
|
|
@ -103,6 +103,8 @@ export function host(overrides: Overrides = {}): Plugin.Context {
|
|||
hook: overrides.session?.hook ?? (() => Effect.die("unused session.hook")),
|
||||
create: overrides.session?.create ?? (() => Effect.die("unused session.create")),
|
||||
get: overrides.session?.get ?? (() => Effect.die("unused session.get")),
|
||||
list: overrides.session?.list ?? (() => Effect.die("unused session.list")),
|
||||
messages: overrides.session?.messages ?? (() => Effect.die("unused session.messages")),
|
||||
prompt: overrides.session?.prompt ?? (() => Effect.die("unused session.prompt")),
|
||||
generate: overrides.session?.generate ?? (() => Effect.die("unused session.generate")),
|
||||
command: overrides.session?.command ?? (() => Effect.die("unused session.command")),
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
import type { SessionApi } from "@opencode-ai/client/effect/api"
|
||||
import type { MessageApi, SessionApi } from "@opencode-ai/client/effect/api"
|
||||
import type { Message, SystemPart } from "@opencode-ai/ai"
|
||||
import type { HttpRequest } from "@opencode-ai/ai/route"
|
||||
import type { Agent } from "@opencode-ai/schema/agent"
|
||||
|
|
@ -29,7 +29,9 @@ export interface SessionHooks {
|
|||
|
||||
export type SessionDomain = Pick<
|
||||
SessionApi<unknown>,
|
||||
"create" | "get" | "prompt" | "generate" | "command" | "synthetic" | "interrupt" | "rename" | "wait"
|
||||
"create" | "get" | "list" | "prompt" | "generate" | "command" | "synthetic" | "interrupt" | "rename" | "wait"
|
||||
> & {
|
||||
readonly hook: Hooks<SessionHooks>
|
||||
/** Read a session's projected message history, paginated like the HTTP message list endpoint. */
|
||||
readonly messages: MessageApi<unknown>["list"]
|
||||
}
|
||||
|
|
|
|||
2
packages/www/content/docs/build/plugins.mdx
vendored
2
packages/www/content/docs/build/plugins.mdx
vendored
|
|
@ -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`, `rename`, `synthetic`, `interrupt`, `wait`, and `hook` |
|
||||
| `ctx.session` | `create`, `get`, `list`, `messages`, `prompt`, `command`, `rename`, `synthetic`, `interrupt`, `wait`, and `hook` |
|
||||
| `ctx.skill` | `list`, `transform`, `reload` |
|
||||
| `ctx.tool` | `transform` and `hook` |
|
||||
| `ctx.aisdk` | `hook` |
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue