refactor(core): simplify integration credentials (#31968)
This commit is contained in:
parent
a9c810cbbc
commit
30aec297d8
112 changed files with 2467 additions and 47728 deletions
|
|
@ -2,7 +2,7 @@ export * as PluginBoot from "./boot"
|
|||
|
||||
import { Context, Deferred, Effect, Layer } from "effect"
|
||||
import { Credential } from "../credential"
|
||||
import { Connector } from "../connector"
|
||||
import { Integration } from "../integration"
|
||||
import { AgentV2 } from "../agent"
|
||||
import { Catalog } from "../catalog"
|
||||
import { CommandV2 } from "../command"
|
||||
|
|
@ -34,7 +34,7 @@ type Plugin = {
|
|||
| Catalog.Service
|
||||
| CommandV2.Service
|
||||
| Credential.Service
|
||||
| Connector.Service
|
||||
| Integration.Service
|
||||
| AgentV2.Service
|
||||
| Npm.Service
|
||||
| EventV2.Service
|
||||
|
|
@ -62,7 +62,7 @@ export const layer = Layer.effect(
|
|||
const commands = yield* CommandV2.Service
|
||||
const plugin = yield* PluginV2.Service
|
||||
const credentials = yield* Credential.Service
|
||||
const connectors = yield* Connector.Service
|
||||
const integrations = yield* Integration.Service
|
||||
const agents = yield* AgentV2.Service
|
||||
const config = yield* Config.Service
|
||||
const location = yield* Location.Service
|
||||
|
|
@ -82,7 +82,7 @@ export const layer = Layer.effect(
|
|||
Effect.provideService(Catalog.Service, catalog),
|
||||
Effect.provideService(CommandV2.Service, commands),
|
||||
Effect.provideService(Credential.Service, credentials),
|
||||
Effect.provideService(Connector.Service, connectors),
|
||||
Effect.provideService(Integration.Service, integrations),
|
||||
Effect.provideService(AgentV2.Service, agents),
|
||||
Effect.provideService(Config.Service, config),
|
||||
Effect.provideService(Location.Service, location),
|
||||
|
|
@ -127,7 +127,7 @@ export const layer = Layer.effect(
|
|||
)
|
||||
|
||||
export const locationLayer = layer.pipe(
|
||||
Layer.provideMerge(Connector.locationLayer),
|
||||
Layer.provideMerge(Integration.locationLayer),
|
||||
Layer.provideMerge(Catalog.locationLayer),
|
||||
Layer.provideMerge(CommandV2.locationLayer),
|
||||
Layer.provideMerge(Config.locationLayer),
|
||||
|
|
|
|||
|
|
@ -1,7 +1,6 @@
|
|||
import { DateTime, Effect, Scope, Stream } from "effect"
|
||||
import { Catalog } from "../catalog"
|
||||
import { Connector } from "../connector"
|
||||
import { Credential } from "../credential"
|
||||
import { Integration } from "../integration"
|
||||
import { EventV2 } from "../event"
|
||||
import { ModelV2 } from "../model"
|
||||
import { ModelRequest } from "../model-request"
|
||||
|
|
@ -56,27 +55,31 @@ export const ModelsDevPlugin = PluginV2.define({
|
|||
id: PluginV2.ID.make("models-dev"),
|
||||
effect: Effect.gen(function* () {
|
||||
const catalog = yield* Catalog.Service
|
||||
const connectors = yield* Connector.Service
|
||||
const integrations = yield* Integration.Service
|
||||
const modelsDev = yield* ModelsDev.Service
|
||||
const events = yield* EventV2.Service
|
||||
const scope = yield* Scope.Scope
|
||||
const transform = yield* catalog.transform()
|
||||
const connectorTransform = yield* connectors.transform()
|
||||
const integrationTransform = yield* integrations.transform()
|
||||
const refresh = Effect.fn("ModelsDevPlugin.refresh")(function* () {
|
||||
const data = yield* modelsDev.get()
|
||||
yield* connectorTransform((connectors) => {
|
||||
yield* integrationTransform((integrations) => {
|
||||
for (const item of Object.values(data)) {
|
||||
if (item.env.length === 0) continue
|
||||
const connectorID = Connector.ID.make(item.id)
|
||||
connectors.update(connectorID, (connector) => (connector.name = item.name))
|
||||
connectors.method.update({
|
||||
connectorID,
|
||||
method: new Connector.KeyMethod({
|
||||
id: Connector.MethodID.make("api-key"),
|
||||
const integrationID = Integration.ID.make(item.id)
|
||||
integrations.update(integrationID, (integration) => (integration.name = item.name))
|
||||
integrations.method.update({
|
||||
integrationID,
|
||||
method: new Integration.KeyMethod({
|
||||
type: "key",
|
||||
label: "API Key",
|
||||
}),
|
||||
authorize: (key: string) => Effect.succeed(new Credential.Key({ type: "key", key })),
|
||||
})
|
||||
integrations.method.update({
|
||||
integrationID,
|
||||
method: new Integration.EnvMethod({
|
||||
type: "env",
|
||||
names: [...item.env],
|
||||
}),
|
||||
})
|
||||
}
|
||||
})
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
import { createServer } from "node:http"
|
||||
import { Deferred, Effect } from "effect"
|
||||
import { Connector } from "../../connector"
|
||||
import { Integration } from "../../integration"
|
||||
import { Credential } from "../../credential"
|
||||
import { InstallationVersion } from "../../installation/version"
|
||||
|
||||
|
|
@ -27,10 +27,13 @@ type Claims = {
|
|||
"https://api.openai.com/auth"?: { chatgpt_account_id?: string }
|
||||
}
|
||||
|
||||
const browserMethodID = Integration.MethodID.make("chatgpt-browser")
|
||||
const headlessMethodID = Integration.MethodID.make("chatgpt-headless")
|
||||
|
||||
export const browser = {
|
||||
connectorID: Connector.ID.make("openai"),
|
||||
method: new Connector.OAuthMethod({
|
||||
id: Connector.MethodID.make("chatgpt-browser"),
|
||||
integrationID: Integration.ID.make("openai"),
|
||||
method: new Integration.OAuthMethod({
|
||||
id: browserMethodID,
|
||||
type: "oauth",
|
||||
label: "ChatGPT Pro/Plus (browser)",
|
||||
}),
|
||||
|
|
@ -77,17 +80,17 @@ export const browser = {
|
|||
instructions: "Complete authorization in your browser. This window will close automatically.",
|
||||
callback: Deferred.await(code).pipe(
|
||||
Effect.flatMap((value) => exchange(value, redirect, pkce)),
|
||||
Effect.map(credential),
|
||||
Effect.map((tokens) => credential(browserMethodID, tokens)),
|
||||
),
|
||||
}
|
||||
}),
|
||||
refresh: (value) => refresh(value),
|
||||
} satisfies Connector.OAuthImplementation
|
||||
} satisfies Integration.OAuthImplementation
|
||||
|
||||
export const headless = {
|
||||
connectorID: Connector.ID.make("openai"),
|
||||
method: new Connector.OAuthMethod({
|
||||
id: Connector.MethodID.make("chatgpt-headless"),
|
||||
integrationID: Integration.ID.make("openai"),
|
||||
method: new Integration.OAuthMethod({
|
||||
id: headlessMethodID,
|
||||
type: "oauth",
|
||||
label: "ChatGPT Pro/Plus (headless)",
|
||||
}),
|
||||
|
|
@ -124,6 +127,7 @@ export const headless = {
|
|||
code_verifier: string
|
||||
}
|
||||
return credential(
|
||||
headlessMethodID,
|
||||
yield* exchange(data.authorization_code, `${issuer}/deviceauth/callback`, {
|
||||
verifier: data.code_verifier,
|
||||
challenge: "",
|
||||
|
|
@ -139,7 +143,7 @@ export const headless = {
|
|||
}
|
||||
}),
|
||||
refresh: (value) => refresh(value),
|
||||
} satisfies Connector.OAuthImplementation
|
||||
} satisfies Integration.OAuthImplementation
|
||||
|
||||
function headers(contentType: string) {
|
||||
return { "Content-Type": contentType, "User-Agent": `opencode/${InstallationVersion}` }
|
||||
|
|
@ -170,7 +174,7 @@ function refresh(value: Credential.OAuth) {
|
|||
}).toString(),
|
||||
}).pipe(
|
||||
Effect.map((tokens) => {
|
||||
const next = credential(tokens)
|
||||
const next = credential(value.methodID, tokens)
|
||||
return new Credential.OAuth({
|
||||
...next,
|
||||
metadata: next.metadata ?? value.metadata,
|
||||
|
|
@ -190,10 +194,11 @@ function request<A>(url: string, init: RequestInit) {
|
|||
})
|
||||
}
|
||||
|
||||
function credential(tokens: TokenResponse) {
|
||||
function credential(methodID: Integration.MethodID, tokens: TokenResponse) {
|
||||
const accountID = extractAccountID(tokens)
|
||||
return new Credential.OAuth({
|
||||
type: "oauth",
|
||||
methodID,
|
||||
refresh: tokens.refresh_token,
|
||||
access: tokens.access_token,
|
||||
expires: Date.now() + (tokens.expires_in ?? 3600) * 1000,
|
||||
|
|
|
|||
|
|
@ -2,14 +2,14 @@ import { Effect } from "effect"
|
|||
import { ModelV2 } from "../../model"
|
||||
import { PluginV2 } from "../../plugin"
|
||||
import { ProviderV2 } from "../../provider"
|
||||
import { Connector } from "../../connector"
|
||||
import { Integration } from "../../integration"
|
||||
import { browser, headless } from "./openai-auth"
|
||||
|
||||
export const OpenAIPlugin = PluginV2.define({
|
||||
id: PluginV2.ID.make("openai"),
|
||||
effect: Effect.gen(function* () {
|
||||
const connectors = yield* Connector.Service
|
||||
yield* connectors.update((editor) => {
|
||||
const integrations = yield* Integration.Service
|
||||
yield* integrations.update((editor) => {
|
||||
editor.method.update(browser)
|
||||
editor.method.update(headless)
|
||||
})
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue