| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159 |
- import { Account } from "@/account/account"
- import { Config } from "@/config"
- import { MCP } from "@/mcp"
- import { ToolRegistry } from "@/tool"
- import { Effect, Layer, Option, Schema } from "effect"
- import { HttpApi, HttpApiBuilder, HttpApiEndpoint, HttpApiGroup, OpenApi } from "effect/unstable/httpapi"
- import { Authorization } from "./auth"
- const ConsoleStateResponse = Schema.Struct({
- consoleManagedProviders: Schema.mutable(Schema.Array(Schema.String)),
- activeOrgName: Schema.optionalKey(Schema.String),
- switchableOrgCount: Schema.Number,
- }).annotate({ identifier: "ConsoleState" })
- const ConsoleOrgOption = Schema.Struct({
- accountID: Schema.String,
- accountEmail: Schema.String,
- accountUrl: Schema.String,
- orgID: Schema.String,
- orgName: Schema.String,
- active: Schema.Boolean,
- }).annotate({ identifier: "ConsoleOrgOption" })
- const ConsoleOrgList = Schema.Struct({
- orgs: Schema.Array(ConsoleOrgOption),
- }).annotate({ identifier: "ConsoleOrgList" })
- const ToolIDs = Schema.Array(Schema.String).annotate({ identifier: "ToolIDs" })
- export const ExperimentalPaths = {
- console: "/experimental/console",
- consoleOrgs: "/experimental/console/orgs",
- toolIDs: "/experimental/tool/ids",
- resource: "/experimental/resource",
- } as const
- export const ExperimentalApi = HttpApi.make("experimental")
- .add(
- HttpApiGroup.make("experimental")
- .add(
- HttpApiEndpoint.get("console", ExperimentalPaths.console, {
- success: ConsoleStateResponse,
- }).annotateMerge(
- OpenApi.annotations({
- identifier: "experimental.console.get",
- summary: "Get active Console provider metadata",
- description: "Get the active Console org name and the set of provider IDs managed by that Console org.",
- }),
- ),
- HttpApiEndpoint.get("consoleOrgs", ExperimentalPaths.consoleOrgs, {
- success: ConsoleOrgList,
- }).annotateMerge(
- OpenApi.annotations({
- identifier: "experimental.console.listOrgs",
- summary: "List switchable Console orgs",
- description: "Get the available Console orgs across logged-in accounts, including the current active org.",
- }),
- ),
- HttpApiEndpoint.get("toolIDs", ExperimentalPaths.toolIDs, {
- success: ToolIDs,
- }).annotateMerge(
- OpenApi.annotations({
- identifier: "tool.ids",
- summary: "List tool IDs",
- description:
- "Get a list of all available tool IDs, including both built-in tools and dynamically registered tools.",
- }),
- ),
- HttpApiEndpoint.get("resource", ExperimentalPaths.resource, {
- success: Schema.Record(Schema.String, MCP.Resource),
- }).annotateMerge(
- OpenApi.annotations({
- identifier: "experimental.resource.list",
- summary: "Get MCP resources",
- description: "Get all available MCP resources from connected servers. Optionally filter by name.",
- }),
- ),
- )
- .annotateMerge(
- OpenApi.annotations({
- title: "experimental",
- description: "Experimental HttpApi read-only routes.",
- }),
- )
- .middleware(Authorization),
- )
- .annotateMerge(
- OpenApi.annotations({
- title: "opencode experimental HttpApi",
- version: "0.0.1",
- description: "Experimental HttpApi surface for selected instance routes.",
- }),
- )
- export const experimentalHandlers = Layer.unwrap(
- Effect.gen(function* () {
- const account = yield* Account.Service
- const config = yield* Config.Service
- const mcp = yield* MCP.Service
- const registry = yield* ToolRegistry.Service
- const getConsole = Effect.fn("ExperimentalHttpApi.console")(function* () {
- const [state, groups] = yield* Effect.all(
- [config.getConsoleState(), account.orgsByAccount().pipe(Effect.orDie)],
- {
- concurrency: "unbounded",
- },
- )
- return {
- consoleManagedProviders: state.consoleManagedProviders,
- ...(state.activeOrgName ? { activeOrgName: state.activeOrgName } : {}),
- switchableOrgCount: groups.reduce((count, group) => count + group.orgs.length, 0),
- }
- })
- const listConsoleOrgs = Effect.fn("ExperimentalHttpApi.consoleOrgs")(function* () {
- const [groups, active] = yield* Effect.all(
- [account.orgsByAccount().pipe(Effect.orDie), account.active().pipe(Effect.orDie)],
- {
- concurrency: "unbounded",
- },
- )
- const info = Option.getOrUndefined(active)
- return {
- orgs: groups.flatMap((group) =>
- group.orgs.map((org) => ({
- accountID: group.account.id,
- accountEmail: group.account.email,
- accountUrl: group.account.url,
- orgID: org.id,
- orgName: org.name,
- active: !!info && info.id === group.account.id && info.active_org_id === org.id,
- })),
- ),
- }
- })
- const toolIDs = Effect.fn("ExperimentalHttpApi.toolIDs")(function* () {
- return yield* registry.ids()
- })
- const resource = Effect.fn("ExperimentalHttpApi.resource")(function* () {
- return yield* mcp.resources()
- })
- return HttpApiBuilder.group(ExperimentalApi, "experimental", (handlers) =>
- handlers
- .handle("console", getConsole)
- .handle("consoleOrgs", listConsoleOrgs)
- .handle("toolIDs", toolIDs)
- .handle("resource", resource),
- )
- }),
- ).pipe(
- Layer.provide(Account.defaultLayer),
- Layer.provide(Config.defaultLayer),
- Layer.provide(MCP.defaultLayer),
- Layer.provide(ToolRegistry.defaultLayer),
- )
|