Download packages/core/src/plugin/provider/opencode.ts from SaylorTwift/opencode: direct link, hf CLI and curl.
- Browser
- Download file 13.3 kB
-
https://huggingface.co/SaylorTwift/opencode/resolve/main/packages/core/src/plugin/provider/opencode.ts
- Command line
-
hf download hf://SaylorTwift/opencode/packages/core/src/plugin/provider/opencode.ts
-
curl -L -o opencode.ts https://huggingface.co/SaylorTwift/opencode/resolve/main/packages/core/src/plugin/provider/opencode.ts
13.3 kB
| import { Duration, Effect, Schema, Semaphore, Stream } from "effect" | |
| import type { Scope } from "effect" | |
| import type { IntegrationOAuthMethodRegistration } from "@opencode-ai/plugin/v2/effect/integration" | |
| import { define } from "@opencode-ai/plugin/v2/effect/plugin" | |
| import type { CredentialValue } from "@opencode-ai/sdk/v2/types" | |
| import { HttpClient, HttpClientRequest, HttpClientResponse } from "effect/unstable/http" | |
| import { EventV2 } from "../../event" | |
| import { Credential } from "../../credential" | |
| import { Integration } from "../../integration" | |
| import { ModelV2 } from "../../model" | |
| import { ProviderV2 } from "../../provider" | |
| import { ConfigProviderV1 } from "../../v1/config/provider" | |
| import { ConfigProviderOptionsV1 } from "../../v1/config/provider-options" | |
| import { ConfigV1 } from "../../v1/config/config" | |
| const defaultServer = "https://opencode.ai/console" | |
| const clientID = "opencode-cli" | |
| const methodID = Integration.MethodID.make("device") | |
| const RemoteResponse = Schema.Struct({ config: ConfigV1.Info }) | |
| const Device = Schema.Struct({ | |
| device_code: Schema.String, | |
| user_code: Schema.String, | |
| verification_uri_complete: Schema.String, | |
| expires_in: Schema.Number, | |
| interval: Schema.Number, | |
| }) | |
| const Token = Schema.Struct({ | |
| access_token: Schema.String, | |
| refresh_token: Schema.String, | |
| expires_in: Schema.Number, | |
| }) | |
| const TokenPending = Schema.Struct({ error: Schema.String }) | |
| const DeviceToken = Schema.Union([Token, TokenPending]) | |
| const User = Schema.Struct({ id: Schema.String, email: Schema.String }) | |
| const Org = Schema.Struct({ id: Schema.String, name: Schema.String }) | |
| function oauth(http: HttpClient.HttpClient) { | |
| return { | |
| integrationID: Integration.ID.make("opencode"), | |
| method: { | |
| id: methodID, | |
| type: "oauth", | |
| label: "OpenCode Console account", | |
| }, | |
| authorize: () => | |
| Effect.gen(function* () { | |
| const device = yield* post(http, `${defaultServer}/auth/device/code`, { client_id: clientID }, Device) | |
| const verification = yield* Effect.try({ | |
| try: () => { | |
| const url = new URL(device.verification_uri_complete, `${defaultServer}/`) | |
| if (url.protocol !== "http:" && url.protocol !== "https:") throw new Error("expected HTTP(S)") | |
| return url | |
| }, | |
| catch: (cause) => | |
| new Error(`Invalid device verification URL: ${cause instanceof Error ? cause.message : String(cause)}`), | |
| }) | |
| return { | |
| mode: "auto" as const, | |
| url: verification.href, | |
| instructions: `Enter code: ${device.user_code}`, | |
| callback: poll(http, defaultServer, device.device_code, Duration.seconds(device.interval)), | |
| } | |
| }), | |
| refresh: (credential) => | |
| Effect.gen(function* () { | |
| const server = typeof credential.metadata?.server === "string" ? credential.metadata.server : defaultServer | |
| const token = yield* post( | |
| http, | |
| `${server}/auth/device/token`, | |
| { grant_type: "refresh_token", refresh_token: credential.refresh, client_id: clientID }, | |
| Token, | |
| ) | |
| return { | |
| ...credential, | |
| access: token.access_token, | |
| refresh: token.refresh_token, | |
| expires: Date.now() + token.expires_in * 1000, | |
| } | |
| }), | |
| label: (credential) => { | |
| return typeof credential.metadata?.orgName === "string" ? credential.metadata.orgName : undefined | |
| }, | |
| } satisfies IntegrationOAuthMethodRegistration | |
| } | |
| export const OpencodePlugin = define<HttpClient.HttpClient | EventV2.Service | Scope.Scope>({ | |
| id: "opencode", | |
| effect: Effect.fn(function* (ctx) { | |
| const events = yield* EventV2.Service | |
| const http = yield* HttpClient.HttpClient | |
| const loading = Semaphore.makeUnsafe(1) | |
| let connected = false | |
| let providers: typeof ConfigV1.Info.Type.provider | undefined | |
| const load = Effect.fn("OpencodePlugin.load")(function* () { | |
| const connection = yield* ctx.integration.connection.active("opencode") | |
| const credential = connection | |
| ? yield* ctx.integration.connection.resolve(connection).pipe(Effect.catch(() => Effect.succeed(undefined))) | |
| : undefined | |
| connected = connection !== undefined | |
| providers = credential | |
| ? yield* fetchProviders(http, credential).pipe( | |
| Effect.catch((cause) => | |
| Effect.logWarning("failed to load OpenCode provider config", { cause }).pipe(Effect.as(undefined)), | |
| ), | |
| ) | |
| : undefined | |
| }) | |
| yield* ctx.integration.transform((draft) => { | |
| draft.update("opencode", (integration) => { | |
| integration.name = "OpenCode" | |
| }) | |
| draft.method.update(oauth(http)) | |
| draft.method.update({ integrationID: "opencode", method: { type: "key", label: "API key (service account)" } }) | |
| }) | |
| connected = (yield* ctx.integration.connection.active("opencode")) !== undefined | |
| yield* ctx.catalog.transform((catalog) => { | |
| for (const [providerID, item] of Object.entries(providers ?? {})) { | |
| catalog.provider.update(providerID, (provider) => { | |
| provider.integrationID = Integration.ID.make("opencode") | |
| if (item.name !== undefined) provider.name = item.name | |
| provider.api = item.npm | |
| ? { type: "aisdk", package: item.npm, url: item.api } | |
| : { type: "native", url: item.api, settings: {} } | |
| Object.assign(provider.request.headers, item.options?.headers) | |
| Object.assign(provider.request.body, withoutCredentials(item.options)) | |
| }) | |
| for (const [modelID, config] of Object.entries(item.models ?? {})) { | |
| catalog.model.update(providerID, modelID, (model) => { | |
| if (config.family !== undefined) model.family = config.family | |
| if (config.name !== undefined) model.name = config.name | |
| if (config.id !== undefined) model.api.id = config.id | |
| if (config.provider !== undefined) { | |
| model.api = config.provider.npm | |
| ? { | |
| id: model.api.id, | |
| type: "aisdk", | |
| package: config.provider.npm, | |
| url: config.provider.api, | |
| } | |
| : { id: model.api.id, type: "native", url: config.provider.api, settings: {} } | |
| } | |
| if (config.tool_call !== undefined) model.capabilities.tools = config.tool_call | |
| if (config.modalities?.input !== undefined) model.capabilities.input = [...config.modalities.input] | |
| if (config.modalities?.output !== undefined) model.capabilities.output = [...config.modalities.output] | |
| const packageName = config.provider?.npm ?? item.npm | |
| const lowerer = ConfigProviderOptionsV1.get(packageName) | |
| Object.assign(model.request.headers, config.headers) | |
| Object.assign(model.request.body, lowerer.request(withoutCredentials(config.options))) | |
| if (config.variants !== undefined) { | |
| model.variants = Object.entries(config.variants).map(([id, options]) => ({ | |
| id: ModelV2.VariantID.make(id), | |
| headers: { ...(options.headers ?? {}) }, | |
| body: lowerer.request(withoutCredentials(options)), | |
| })) | |
| } | |
| if (config.release_date !== undefined) { | |
| const released = Date.parse(config.release_date) | |
| model.time.released = Number.isFinite(released) ? released : 0 | |
| } | |
| if (config.cost !== undefined) { | |
| model.cost = remoteCost(config.cost) | |
| } | |
| model.status = config.status ?? "active" | |
| model.enabled = config.status !== "deprecated" | |
| if (config.limit !== undefined) model.limit = { ...config.limit } | |
| }) | |
| } | |
| } | |
| const item = catalog.provider.get(ProviderV2.ID.opencode) | |
| if (!item) return | |
| const hasKey = Boolean(process.env.OPENCODE_API_KEY || connected || item.provider.request.body.apiKey) | |
| catalog.provider.update(item.provider.id, (provider) => { | |
| if (!hasKey) provider.request.body.apiKey = "public" | |
| }) | |
| if (hasKey) return | |
| for (const model of item.models.values()) { | |
| if (!model.cost.some((cost) => cost.input > 0)) continue | |
| catalog.model.update(item.provider.id, model.id, (draft) => { | |
| draft.enabled = false | |
| }) | |
| } | |
| }) | |
| const refresh = () => loading.withPermit(load().pipe(Effect.andThen(ctx.catalog.reload()))) | |
| yield* events.subscribe(Integration.Event.ConnectionUpdated).pipe( | |
| Stream.filter((event) => event.data.integrationID === Integration.ID.make("opencode")), | |
| Stream.runForEach(refresh), | |
| Effect.forkScoped({ startImmediately: true }), | |
| ) | |
| yield* refresh().pipe(Effect.forkScoped) | |
| }), | |
| }) | |
| function fetchProviders(http: HttpClient.HttpClient, value: CredentialValue) { | |
| const metadata = value.metadata | |
| const server = typeof metadata?.server === "string" ? metadata.server : defaultServer | |
| const orgID = typeof metadata?.orgID === "string" ? metadata.orgID : undefined | |
| const token = value.type === "oauth" ? value.access : value.key | |
| return http | |
| .execute( | |
| HttpClientRequest.get(`${server}/api/config`).pipe( | |
| HttpClientRequest.acceptJson, | |
| HttpClientRequest.bearerToken(token), | |
| HttpClientRequest.setHeaders(orgID ? { "x-org-id": orgID } : {}), | |
| ), | |
| ) | |
| .pipe( | |
| Effect.flatMap((response) => { | |
| if (response.status === 404) return Effect.succeed(undefined) | |
| return HttpClientResponse.filterStatusOk(response).pipe( | |
| Effect.flatMap(HttpClientResponse.schemaBodyJson(RemoteResponse)), | |
| Effect.map((remote) => remote.config.provider), | |
| ) | |
| }), | |
| ) | |
| } | |
| function withoutCredentials(body: Readonly<Record<string, unknown>> | undefined) { | |
| return Object.fromEntries(Object.entries(body ?? {}).filter(([key]) => key !== "apiKey" && key !== "headers")) | |
| } | |
| function remoteCost(input: NonNullable<(typeof ConfigProviderV1.Model.Type)["cost"]>) { | |
| const base = { | |
| input: input.input, | |
| output: input.output, | |
| cache: { read: input.cache_read ?? 0, write: input.cache_write ?? 0 }, | |
| } | |
| if (!input.context_over_200k) return [base] | |
| return [ | |
| base, | |
| { | |
| tier: { type: "context" as const, size: 200_000 }, | |
| input: input.context_over_200k.input, | |
| output: input.context_over_200k.output, | |
| cache: { | |
| read: input.context_over_200k.cache_read ?? 0, | |
| write: input.context_over_200k.cache_write ?? 0, | |
| }, | |
| }, | |
| ] | |
| } | |
| function poll(http: HttpClient.HttpClient, server: string, deviceCode: string, interval: Duration.Duration) { | |
| const loop = (wait: Duration.Duration): Effect.Effect<Credential.OAuth, unknown> => | |
| Effect.gen(function* () { | |
| yield* Effect.sleep(wait) | |
| const result = yield* post( | |
| http, | |
| `${server}/auth/device/token`, | |
| { | |
| grant_type: "urn:ietf:params:oauth:grant-type:device_code", | |
| device_code: deviceCode, | |
| client_id: clientID, | |
| }, | |
| DeviceToken, | |
| false, | |
| ) | |
| if ("access_token" in result) return yield* credential(http, server, result) | |
| if (result.error === "authorization_pending") return yield* loop(wait) | |
| if (result.error === "slow_down") { | |
| return yield* loop(Duration.sum(wait, Duration.seconds(5))) | |
| } | |
| return yield* Effect.fail(new Error(`Device authorization failed: ${result.error}`)) | |
| }) | |
| return loop(interval) | |
| } | |
| function credential(http: HttpClient.HttpClient, server: string, token: typeof Token.Type) { | |
| return Effect.gen(function* () { | |
| const [user, orgs] = yield* Effect.all( | |
| [ | |
| get(http, `${server}/api/user`, token.access_token, User), | |
| get(http, `${server}/api/orgs`, token.access_token, Schema.Array(Org)), | |
| ], | |
| { concurrency: 2 }, | |
| ) | |
| const org = orgs.toSorted((a, b) => a.name.localeCompare(b.name) || a.id.localeCompare(b.id))[0] | |
| return Credential.OAuth.make({ | |
| type: "oauth" as const, | |
| methodID, | |
| access: token.access_token, | |
| refresh: token.refresh_token, | |
| expires: Date.now() + token.expires_in * 1000, | |
| metadata: { | |
| server, | |
| accountID: user.id, | |
| email: user.email, | |
| orgID: org?.id, | |
| orgName: org?.name, | |
| }, | |
| }) | |
| }) | |
| } | |
| function get<S extends Schema.Top>(http: HttpClient.HttpClient, url: string, token: string, schema: S) { | |
| return HttpClient.filterStatusOk(http) | |
| .execute(HttpClientRequest.get(url).pipe(HttpClientRequest.acceptJson, HttpClientRequest.bearerToken(token))) | |
| .pipe(Effect.flatMap(HttpClientResponse.schemaBodyJson(schema))) | |
| } | |
| function post<S extends Schema.Top>( | |
| http: HttpClient.HttpClient, | |
| url: string, | |
| body: Record<string, string>, | |
| schema: S, | |
| statusOk = true, | |
| ) { | |
| return HttpClientRequest.post(url).pipe( | |
| HttpClientRequest.acceptJson, | |
| HttpClientRequest.schemaBodyJson(Schema.Record(Schema.String, Schema.String))(body), | |
| Effect.flatMap((request) => http.execute(request)), | |
| Effect.flatMap((response) => (statusOk ? HttpClientResponse.filterStatusOk(response) : Effect.succeed(response))), | |
| Effect.flatMap(HttpClientResponse.schemaBodyJson(schema)), | |
| ) | |
| } | |