feat(core): expose server API in Code Mode
This commit is contained in:
parent
93b7ca9b4d
commit
e113aad5e0
6 changed files with 139 additions and 21 deletions
|
|
@ -52,8 +52,25 @@ function listen(options: Options) {
|
|||
|
||||
function bind(hostname: string, port: number, password: string) {
|
||||
const server = createServer()
|
||||
const codeModeClient = Layer.effect(
|
||||
HttpClient.HttpClient,
|
||||
Effect.gen(function* () {
|
||||
const client = yield* HttpClient.HttpClient
|
||||
return HttpClient.mapRequest(client, (request) => {
|
||||
const address = server.address()
|
||||
if (!address || typeof address === "string") throw new Error("OpenCode server is not listening")
|
||||
const local = hostname === "0.0.0.0" ? "127.0.0.1" : hostname === "::" ? "::1" : hostname
|
||||
const host = local.includes(":") && !local.startsWith("[") ? `[${local}]` : local
|
||||
const url = new URL(request.url)
|
||||
return HttpClientRequest.setUrl(
|
||||
request,
|
||||
new URL(`${url.pathname}${url.search}${url.hash}`, `http://${host}:${address.port}`),
|
||||
)
|
||||
})
|
||||
}),
|
||||
).pipe(Layer.provide(NodeHttpClient.layerNodeHttp))
|
||||
return Layer.build(
|
||||
HttpRouter.serve(createRoutes(password), { disableListenLog: true }).pipe(
|
||||
HttpRouter.serve(createRoutes(password, codeModeClient), { disableListenLog: true }).pipe(
|
||||
Layer.provideMerge(NodeHttpServer.layer(() => server, { port, host: hostname })),
|
||||
Layer.provide(AppNodeBuilder.build(LayerNode.group([Credential.node, PermissionSaved.node, Project.node]))),
|
||||
),
|
||||
|
|
|
|||
|
|
@ -17,8 +17,10 @@ import { SessionExecutionLocal } from "@opencode-ai/core/session/execution/local
|
|||
import { PluginRuntime } from "@opencode-ai/core/plugin/runtime"
|
||||
import { SdkPlugins } from "@opencode-ai/core/plugin/sdk"
|
||||
import { ToolOutputStore } from "@opencode-ai/core/tool-output-store"
|
||||
import { HttpRouter, HttpServer } from "effect/unstable/http"
|
||||
import { HttpApiBuilder } from "effect/unstable/httpapi"
|
||||
import { ToolRegistry } from "@opencode-ai/core/tool/registry"
|
||||
import { OpenAPI, Tool } from "@opencode-ai/codemode"
|
||||
import { HttpClient, HttpRouter, HttpServer } from "effect/unstable/http"
|
||||
import { HttpApiBuilder, OpenApi } from "effect/unstable/httpapi"
|
||||
import { Effect, Layer, Option } from "effect"
|
||||
import { Api } from "./api"
|
||||
import { ServerAuth } from "./auth"
|
||||
|
|
@ -47,11 +49,24 @@ const applicationServices = LayerNode.group([
|
|||
LocationServiceMap.node,
|
||||
])
|
||||
|
||||
export function createRoutes(password?: string) {
|
||||
export function createRoutes(password?: string, codeModeClient?: Layer.Layer<HttpClient.HttpClient>) {
|
||||
return makeRoutes(
|
||||
password
|
||||
? ServerAuth.Config.configLayer({ username: "opencode", password: Option.some(password) })
|
||||
: ServerAuth.Config.layer,
|
||||
undefined,
|
||||
codeModeClient
|
||||
? {
|
||||
opencode: openCodeTools(
|
||||
OpenAPI.fromSpec({
|
||||
spec: { ...OpenApi.fromApi(Api) },
|
||||
baseUrl: "http://opencode.local",
|
||||
headers: ServerAuth.headers({ username: "opencode", password }),
|
||||
}).tools,
|
||||
codeModeClient,
|
||||
),
|
||||
}
|
||||
: undefined,
|
||||
)
|
||||
}
|
||||
|
||||
|
|
@ -62,13 +77,18 @@ export function createEmbeddedRoutes(sdkPlugins?: SdkPlugins.Store) {
|
|||
function makeRoutes<AuthError, AuthServices>(
|
||||
auth: Layer.Layer<ServerAuth.Config, AuthError, AuthServices>,
|
||||
sdkPlugins?: SdkPlugins.Store,
|
||||
codeModeTools?: ToolRegistry.CodeModeTools,
|
||||
) {
|
||||
const pluginRuntimeCell = PluginRuntime.makeCell()
|
||||
const codeMode = codeModeTools ? ToolRegistry.nodes(codeModeTools) : undefined
|
||||
const replacements: LayerNode.Replacements = [
|
||||
[SessionExecution.node, SessionExecutionLocal.node],
|
||||
[PluginRuntime.node, PluginRuntime.layerWithCell(pluginRuntimeCell)],
|
||||
[PluginRuntime.providerNode, PluginRuntime.providerNodeWithCell(pluginRuntimeCell)],
|
||||
...(sdkPlugins ? [[SdkPlugins.node, SdkPlugins.layerWithStore(sdkPlugins)] as const] : []),
|
||||
...(codeMode
|
||||
? [[ToolRegistry.node, codeMode.node] as const, [ToolRegistry.toolsNode, codeMode.toolsNode] as const]
|
||||
: []),
|
||||
]
|
||||
const serviceLayer = simulateEnabled()
|
||||
? Layer.unwrap(
|
||||
|
|
@ -98,6 +118,22 @@ function makeRoutes<AuthError, AuthServices>(
|
|||
)
|
||||
}
|
||||
|
||||
function openCodeTools(tools: OpenAPI.Tools, client: Layer.Layer<HttpClient.HttpClient>): ToolRegistry.CodeModeTools {
|
||||
return Object.fromEntries(
|
||||
Object.entries(tools).map(([name, value]) => [
|
||||
name,
|
||||
Tool.isDefinition<HttpClient.HttpClient>(value)
|
||||
? Tool.make({
|
||||
description: value.description,
|
||||
input: value.input,
|
||||
output: value.output,
|
||||
run: (input) => value.run(input).pipe(Effect.provide(client)),
|
||||
})
|
||||
: openCodeTools(value, client),
|
||||
]),
|
||||
)
|
||||
}
|
||||
|
||||
function simulateEnabled() {
|
||||
return !!process.env.OPENCODE_SIMULATE
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue