refactor: isolate legacy flags
This commit is contained in:
parent
407ac2d8aa
commit
43c08387f1
65 changed files with 282 additions and 147 deletions
|
|
@ -155,6 +155,8 @@ export interface Interface {
|
|||
|
||||
export const Options = Schema.Struct({
|
||||
project: Schema.optional(Schema.Boolean),
|
||||
file: Schema.optional(Schema.String),
|
||||
content: Schema.optional(Schema.String),
|
||||
})
|
||||
export type Options = typeof Options.Type
|
||||
|
||||
|
|
@ -293,14 +295,39 @@ export const layer = (options?: Options) => Layer.effect(
|
|||
Effect.map((entries) => entries.flat()),
|
||||
)
|
||||
|
||||
const file = options?.file
|
||||
const explicit = file
|
||||
? yield* loadFile(path.resolve(file)).pipe(
|
||||
Effect.map((config) => [
|
||||
...(config ? [config] : []),
|
||||
new File({ type: "file", path: AbsolutePath.make(path.resolve(file)) }),
|
||||
]),
|
||||
Effect.orDie,
|
||||
)
|
||||
: []
|
||||
const content = options?.content
|
||||
? yield* ConfigVariable.substitute({
|
||||
type: "virtual",
|
||||
source: "OPENCODE_CONFIG_CONTENT",
|
||||
dir: location.directory,
|
||||
text: options.content,
|
||||
}).pipe(
|
||||
Effect.map(parseInfo),
|
||||
Effect.map((info) => (info ? [new Document({ type: "document", info })] : [])),
|
||||
Effect.orDie,
|
||||
)
|
||||
: []
|
||||
|
||||
const supplementary = yield* Effect.forEach(directories, loadDirectory).pipe(Effect.orDie)
|
||||
return [
|
||||
...claude,
|
||||
...agents,
|
||||
...(supplementary[0] ?? []),
|
||||
...explicit,
|
||||
...direct,
|
||||
...supplementary.slice(1).flat(),
|
||||
...(yield* loadWellknown().pipe(Effect.orDie)),
|
||||
...content,
|
||||
]
|
||||
})
|
||||
|
||||
|
|
|
|||
|
|
@ -1,84 +0,0 @@
|
|||
import { Config } from "effect"
|
||||
|
||||
export function truthy(key: string) {
|
||||
const value = process.env[key]?.toLowerCase()
|
||||
return value === "true" || value === "1"
|
||||
}
|
||||
|
||||
const copy = process.env["OPENCODE_EXPERIMENTAL_DISABLE_COPY_ON_SELECT"]
|
||||
const fff = process.env["OPENCODE_DISABLE_FFF"]
|
||||
|
||||
function enabledByExperimental(key: string) {
|
||||
return process.env[key] === undefined ? truthy("OPENCODE_EXPERIMENTAL") : truthy(key)
|
||||
}
|
||||
|
||||
export const Flag = {
|
||||
// V2: ServerOptions.observability.endpoint
|
||||
OTEL_EXPORTER_OTLP_ENDPOINT: process.env["OTEL_EXPORTER_OTLP_ENDPOINT"],
|
||||
// V2: ServerOptions.observability.headers
|
||||
OTEL_EXPORTER_OTLP_HEADERS: process.env["OTEL_EXPORTER_OTLP_HEADERS"],
|
||||
|
||||
OPENCODE_AUTO_HEAP_SNAPSHOT: truthy("OPENCODE_AUTO_HEAP_SNAPSHOT"),
|
||||
// V2: ServerOptions.windows.gitbash
|
||||
OPENCODE_GIT_BASH_PATH: process.env["OPENCODE_GIT_BASH_PATH"],
|
||||
OPENCODE_CONFIG: process.env["OPENCODE_CONFIG"],
|
||||
OPENCODE_CONFIG_CONTENT: process.env["OPENCODE_CONFIG_CONTENT"],
|
||||
OPENCODE_DISABLE_AUTOUPDATE: truthy("OPENCODE_DISABLE_AUTOUPDATE"),
|
||||
OPENCODE_ALWAYS_NOTIFY_UPDATE: truthy("OPENCODE_ALWAYS_NOTIFY_UPDATE"),
|
||||
OPENCODE_DISABLE_PRUNE: truthy("OPENCODE_DISABLE_PRUNE"),
|
||||
OPENCODE_DISABLE_TERMINAL_TITLE: truthy("OPENCODE_DISABLE_TERMINAL_TITLE"),
|
||||
OPENCODE_SHOW_TTFD: truthy("OPENCODE_SHOW_TTFD"),
|
||||
OPENCODE_DISABLE_AUTOCOMPACT: truthy("OPENCODE_DISABLE_AUTOCOMPACT"),
|
||||
// V2: ServerOptions.models.fetch
|
||||
OPENCODE_DISABLE_MODELS_FETCH: truthy("OPENCODE_DISABLE_MODELS_FETCH"),
|
||||
OPENCODE_DISABLE_MOUSE: truthy("OPENCODE_DISABLE_MOUSE"),
|
||||
OPENCODE_FAKE_VCS: process.env["OPENCODE_FAKE_VCS"],
|
||||
OPENCODE_SERVER_PASSWORD: process.env["OPENCODE_SERVER_PASSWORD"],
|
||||
OPENCODE_SERVER_USERNAME: process.env["OPENCODE_SERVER_USERNAME"],
|
||||
// V2: ServerOptions.fs.fff
|
||||
OPENCODE_DISABLE_FFF: fff === undefined ? process.platform === "win32" : truthy("OPENCODE_DISABLE_FFF"),
|
||||
// V2: ServerOptions.fs.filewatcher
|
||||
OPENCODE_DISABLE_FILEWATCHER: truthy("OPENCODE_DISABLE_FILEWATCHER"),
|
||||
|
||||
// Experimental
|
||||
OPENCODE_EXPERIMENTAL_DISABLE_COPY_ON_SELECT:
|
||||
copy === undefined ? process.platform === "win32" : truthy("OPENCODE_EXPERIMENTAL_DISABLE_COPY_ON_SELECT"),
|
||||
// V2: ServerOptions.models.url
|
||||
OPENCODE_MODELS_URL: process.env["OPENCODE_MODELS_URL"],
|
||||
// V2: ServerOptions.models.file
|
||||
OPENCODE_MODELS_PATH: process.env["OPENCODE_MODELS_PATH"],
|
||||
// V2: ServerOptions.database.path
|
||||
OPENCODE_DB: process.env["OPENCODE_DB"],
|
||||
|
||||
OPENCODE_WORKSPACE_ID: process.env["OPENCODE_WORKSPACE_ID"],
|
||||
OPENCODE_EXPERIMENTAL_WORKSPACES: enabledByExperimental("OPENCODE_EXPERIMENTAL_WORKSPACES"),
|
||||
|
||||
// Evaluated at access time (not module load) because tests, the CLI, and
|
||||
// external tooling set these env vars at runtime.
|
||||
// V2: ServerOptions.config.project
|
||||
get OPENCODE_DISABLE_PROJECT_CONFIG() {
|
||||
return truthy("OPENCODE_DISABLE_PROJECT_CONFIG")
|
||||
},
|
||||
get OPENCODE_EXPERIMENTAL_REFERENCES() {
|
||||
return enabledByExperimental("OPENCODE_EXPERIMENTAL_REFERENCES")
|
||||
},
|
||||
get OPENCODE_TUI_CONFIG() {
|
||||
return process.env["OPENCODE_TUI_CONFIG"]
|
||||
},
|
||||
// V2: ServerOptions.config.directory
|
||||
get OPENCODE_CONFIG_DIR() {
|
||||
return process.env["OPENCODE_CONFIG_DIR"]
|
||||
},
|
||||
get OPENCODE_PURE() {
|
||||
return truthy("OPENCODE_PURE")
|
||||
},
|
||||
get OPENCODE_PERMISSION() {
|
||||
return process.env["OPENCODE_PERMISSION"]
|
||||
},
|
||||
get OPENCODE_PLUGIN_META_FILE() {
|
||||
return process.env["OPENCODE_PLUGIN_META_FILE"]
|
||||
},
|
||||
get OPENCODE_CLIENT() {
|
||||
return process.env["OPENCODE_CLIENT"] ?? "cli"
|
||||
},
|
||||
}
|
||||
|
|
@ -4,7 +4,6 @@ import { HttpClient, HttpClientRequest } from "effect/unstable/http"
|
|||
import { ModelsDev } from "@opencode-ai/schema/models-dev"
|
||||
import { Money } from "@opencode-ai/schema/money"
|
||||
import { Global } from "./global"
|
||||
import { Flag } from "./flag/flag"
|
||||
import { Flock } from "./util/flock"
|
||||
import { Hash } from "./util/hash"
|
||||
import { FSUtil } from "./fs-util"
|
||||
|
|
@ -18,8 +17,6 @@ import { ProviderV2 } from "./provider"
|
|||
export const CatalogModelStatus = Schema.Literals(["alpha", "beta", "deprecated"])
|
||||
export type CatalogModelStatus = typeof CatalogModelStatus.Type
|
||||
|
||||
const USER_AGENT = `opencode/${InstallationChannel}/${InstallationVersion}/${Flag.OPENCODE_CLIENT}`
|
||||
|
||||
type Cost = {
|
||||
readonly input: Money.USDPerMillionTokens
|
||||
readonly output: Money.USDPerMillionTokens
|
||||
|
|
@ -534,6 +531,7 @@ export const Options = Schema.Struct({
|
|||
url: Schema.optional(Schema.String),
|
||||
file: Schema.optional(Schema.String),
|
||||
fetch: Schema.optional(Schema.Boolean),
|
||||
client: Schema.optional(Schema.String),
|
||||
})
|
||||
export type Options = typeof Options.Type
|
||||
|
||||
|
|
@ -556,6 +554,7 @@ export const layer = (options?: Options) => Layer.effect(
|
|||
|
||||
const source = options?.url ?? "https://models.dev"
|
||||
const fetch = options?.fetch ?? true
|
||||
const userAgent = `opencode/${InstallationChannel}/${InstallationVersion}/${options?.client ?? "cli"}`
|
||||
const filepath = path.join(
|
||||
Global.Path.cache,
|
||||
source === "https://models.dev" ? "models.json" : `models-${Hash.fast(source)}.json`,
|
||||
|
|
@ -572,7 +571,7 @@ export const layer = (options?: Options) => Layer.effect(
|
|||
|
||||
const fetchApi = Effect.fn("ModelsDev.fetchApi")(function* () {
|
||||
return yield* HttpClientRequest.get(`${source}/api.json`).pipe(
|
||||
HttpClientRequest.setHeader("User-Agent", USER_AGENT),
|
||||
HttpClientRequest.setHeader("User-Agent", userAgent),
|
||||
http.execute,
|
||||
Effect.flatMap((res) => res.text),
|
||||
Effect.timeout("10 seconds"),
|
||||
|
|
|
|||
|
|
@ -11,6 +11,7 @@ import { Otlp } from "./observability/otlp"
|
|||
export const Options = Schema.Struct({
|
||||
endpoint: Schema.optional(Schema.String),
|
||||
headers: Schema.optional(Schema.String),
|
||||
client: Schema.optional(Schema.String),
|
||||
})
|
||||
export type Options = typeof Options.Type
|
||||
|
||||
|
|
@ -18,6 +19,7 @@ export function layer(
|
|||
options: Options = {
|
||||
endpoint: process.env.OTEL_EXPORTER_OTLP_ENDPOINT,
|
||||
headers: process.env.OTEL_EXPORTER_OTLP_HEADERS,
|
||||
client: process.env.OPENCODE_CLIENT ?? "cli",
|
||||
},
|
||||
) {
|
||||
const local = Logger.layer(Logging.loggers(), { mergeWithExisting: false }).pipe(
|
||||
|
|
|
|||
|
|
@ -1,12 +1,12 @@
|
|||
import { Layer } from "effect"
|
||||
import { OtlpLogger } from "effect/unstable/observability"
|
||||
import { Flag } from "../flag/flag"
|
||||
import { InstallationChannel, InstallationVersion } from "../installation/version"
|
||||
import { runID } from "./shared"
|
||||
|
||||
export interface Options {
|
||||
readonly endpoint?: string
|
||||
readonly headers?: string
|
||||
readonly client?: string
|
||||
}
|
||||
|
||||
function parseHeaders(value?: string) {
|
||||
|
|
@ -38,14 +38,14 @@ function resourceAttributes() {
|
|||
}
|
||||
}
|
||||
|
||||
export function resource(): { serviceName: string; serviceVersion: string; attributes: Record<string, string> } {
|
||||
export function resource(client = "cli"): { serviceName: string; serviceVersion: string; attributes: Record<string, string> } {
|
||||
return {
|
||||
serviceName: "opencode",
|
||||
serviceVersion: InstallationVersion,
|
||||
attributes: {
|
||||
...resourceAttributes(),
|
||||
"deployment.environment.name": InstallationChannel,
|
||||
"opencode.client": Flag.OPENCODE_CLIENT,
|
||||
"opencode.client": client,
|
||||
"opencode.run": runID,
|
||||
"service.instance.id": runID,
|
||||
},
|
||||
|
|
@ -55,7 +55,11 @@ export function resource(): { serviceName: string; serviceVersion: string; attri
|
|||
export function loggers(options?: Options) {
|
||||
if (!options?.endpoint) return []
|
||||
return [
|
||||
OtlpLogger.make({ url: `${options.endpoint}/v1/logs`, resource: resource(), headers: parseHeaders(options.headers) }),
|
||||
OtlpLogger.make({
|
||||
url: `${options.endpoint}/v1/logs`,
|
||||
resource: resource(options.client),
|
||||
headers: parseHeaders(options.headers),
|
||||
}),
|
||||
]
|
||||
}
|
||||
|
||||
|
|
@ -73,7 +77,7 @@ export async function tracingLayer(options?: Options) {
|
|||
context.setGlobalContextManager(manager)
|
||||
|
||||
return NodeSdk.layer(() => ({
|
||||
resource: resource(),
|
||||
resource: resource(options.client),
|
||||
spanProcessor: new SdkBase.BatchSpanProcessor(
|
||||
new OTLP.OTLPTraceExporter({
|
||||
url: `${options.endpoint}/v1/traces`,
|
||||
|
|
|
|||
|
|
@ -60,6 +60,7 @@ type Settings = {
|
|||
}
|
||||
|
||||
type Dependencies = {
|
||||
readonly headers?: SessionModelHeaders.Options
|
||||
readonly events: EventV2.Interface
|
||||
readonly llm: {
|
||||
readonly stream: (request: LLMRequest) => Stream.Stream<LLMEvent, LLMError>
|
||||
|
|
@ -258,7 +259,7 @@ const make = (dependencies: Dependencies) => {
|
|||
.stream(
|
||||
LLM.request({
|
||||
model: plan.model,
|
||||
http: { headers: SessionModelHeaders.make(plan.session) },
|
||||
http: { headers: SessionModelHeaders.make(plan.session, dependencies.headers) },
|
||||
messages: [Message.user(plan.prompt)],
|
||||
tools: [],
|
||||
}),
|
||||
|
|
@ -390,19 +391,23 @@ const make = (dependencies: Dependencies) => {
|
|||
})
|
||||
}
|
||||
|
||||
export const layer = Layer.effect(
|
||||
export const layer = (options?: SessionModelHeaders.Options) => Layer.effect(
|
||||
Service,
|
||||
Effect.gen(function* () {
|
||||
const events = yield* EventV2.Service
|
||||
const llm = yield* LLMClient.Service
|
||||
const config = yield* Config.Service
|
||||
const models = yield* SessionRunnerModel.Service
|
||||
return make({ events, llm, models, config: settings(yield* config.entries()) })
|
||||
return make({ events, llm, models, config: settings(yield* config.entries()), headers: options })
|
||||
}),
|
||||
)
|
||||
|
||||
export const node = makeLocationNode({
|
||||
service: Service,
|
||||
layer,
|
||||
deps: [EventV2.node, llmClient, Config.node, SessionRunnerModel.node],
|
||||
})
|
||||
export function configured(options?: SessionModelHeaders.Options) {
|
||||
return makeLocationNode({
|
||||
service: Service,
|
||||
layer: layer(options),
|
||||
deps: [EventV2.node, llmClient, Config.node, SessionRunnerModel.node],
|
||||
})
|
||||
}
|
||||
|
||||
export const node = configured()
|
||||
|
|
|
|||
|
|
@ -14,7 +14,7 @@ import { SessionRunnerModel } from "./runner/model"
|
|||
import PROMPT_DEFAULT from "./runner/prompt/base.txt"
|
||||
import { toLLMMessages } from "./runner/to-llm-message"
|
||||
|
||||
const layer = Layer.effect(
|
||||
export const layer = (options?: SessionModelHeaders.Options) => Layer.effect(
|
||||
SessionGenerate.Service,
|
||||
Effect.gen(function* () {
|
||||
const context = yield* SessionContext.Service
|
||||
|
|
@ -49,7 +49,7 @@ const layer = Layer.effect(
|
|||
return (yield* llm.generate(
|
||||
LLM.request({
|
||||
model: model.model,
|
||||
http: { headers: SessionModelHeaders.make(selection.session) },
|
||||
http: { headers: SessionModelHeaders.make(selection.session, options) },
|
||||
providerOptions: { openai: { promptCacheKey } },
|
||||
system: contextEvent.system,
|
||||
messages: contextEvent.messages,
|
||||
|
|
@ -62,8 +62,12 @@ const layer = Layer.effect(
|
|||
}),
|
||||
)
|
||||
|
||||
export const node = makeLocationNode({
|
||||
service: SessionGenerate.Service,
|
||||
layer,
|
||||
deps: [SessionContext.node, Database.node, PluginHooks.node, SessionRunnerModel.node, llmClient],
|
||||
})
|
||||
export function configured(options?: SessionModelHeaders.Options) {
|
||||
return makeLocationNode({
|
||||
service: SessionGenerate.Service,
|
||||
layer: layer(options),
|
||||
deps: [SessionContext.node, Database.node, PluginHooks.node, SessionRunnerModel.node, llmClient],
|
||||
})
|
||||
}
|
||||
|
||||
export const node = configured()
|
||||
|
|
|
|||
|
|
@ -1,15 +1,23 @@
|
|||
export * as SessionModelHeaders from "./model-headers"
|
||||
|
||||
import { Flag } from "../flag/flag"
|
||||
import { InstallationVersion } from "../installation/version"
|
||||
import { SessionSchema } from "./schema"
|
||||
import { Schema } from "effect"
|
||||
|
||||
export const make = (session: Pick<SessionSchema.Info, "id" | "parentID" | "projectID">) => ({
|
||||
export const Options = Schema.Struct({
|
||||
client: Schema.optional(Schema.String),
|
||||
})
|
||||
export type Options = typeof Options.Type
|
||||
|
||||
export const make = (
|
||||
session: Pick<SessionSchema.Info, "id" | "parentID" | "projectID">,
|
||||
options?: Options,
|
||||
) => ({
|
||||
"x-session-affinity": session.id,
|
||||
"X-Session-Id": session.id,
|
||||
...(session.parentID ? { "x-parent-session-id": session.parentID } : {}),
|
||||
"User-Agent": `opencode/${InstallationVersion}`,
|
||||
"x-opencode-project": session.projectID,
|
||||
"x-opencode-session": session.id,
|
||||
"x-opencode-client": Flag.OPENCODE_CLIENT,
|
||||
"x-opencode-client": options?.client ?? "cli",
|
||||
})
|
||||
|
|
|
|||
|
|
@ -39,7 +39,7 @@ export interface Interface {
|
|||
/** Location-scoped outbound model-request preparation. */
|
||||
export class Service extends Context.Service<Service, Interface>()("@opencode/v2/SessionModelRequest") {}
|
||||
|
||||
const layer = Layer.effect(
|
||||
export const layer = (options?: SessionModelHeaders.Options) => Layer.effect(
|
||||
Service,
|
||||
Effect.gen(function* () {
|
||||
const hooks = yield* PluginHooks.Service
|
||||
|
|
@ -81,7 +81,7 @@ const layer = Layer.effect(
|
|||
const request = LLM.request({
|
||||
model,
|
||||
http: {
|
||||
headers: SessionModelHeaders.make(session),
|
||||
headers: SessionModelHeaders.make(session, options),
|
||||
},
|
||||
providerOptions: { openai: { promptCacheKey } },
|
||||
system: contextEvent.system,
|
||||
|
|
@ -112,8 +112,8 @@ const layer = Layer.effect(
|
|||
}),
|
||||
)
|
||||
|
||||
export const node = makeLocationNode({
|
||||
service: Service,
|
||||
layer,
|
||||
deps: [PluginHooks.node, ToolRegistry.node],
|
||||
})
|
||||
export function configured(options?: SessionModelHeaders.Options) {
|
||||
return makeLocationNode({ service: Service, layer: layer(options), deps: [PluginHooks.node, ToolRegistry.node] })
|
||||
}
|
||||
|
||||
export const node = configured()
|
||||
|
|
|
|||
|
|
@ -17,6 +17,7 @@ import { SessionUsage } from "./usage"
|
|||
const MAX_LENGTH = 100
|
||||
|
||||
type Dependencies = {
|
||||
readonly headers?: SessionModelHeaders.Options
|
||||
readonly events: EventV2.Interface
|
||||
readonly llm: {
|
||||
readonly stream: (request: LLMRequest) => Stream.Stream<LLMEvent, LLMError>
|
||||
|
|
@ -66,7 +67,7 @@ const make = (dependencies: Dependencies) => {
|
|||
.stream(
|
||||
LLM.request({
|
||||
model: resolved.model,
|
||||
http: { headers: SessionModelHeaders.make(session) },
|
||||
http: { headers: SessionModelHeaders.make(session, dependencies.headers) },
|
||||
system: agent.system,
|
||||
messages: [Message.user(firstUser.text)],
|
||||
tools: [],
|
||||
|
|
@ -102,7 +103,7 @@ const make = (dependencies: Dependencies) => {
|
|||
return { generateForFirstPrompt }
|
||||
}
|
||||
|
||||
export const layer = Layer.effect(
|
||||
export const layer = (options?: SessionModelHeaders.Options) => Layer.effect(
|
||||
Service,
|
||||
Effect.gen(function* () {
|
||||
const events = yield* EventV2.Service
|
||||
|
|
@ -110,15 +111,19 @@ export const layer = Layer.effect(
|
|||
const agents = yield* AgentV2.Service
|
||||
const models = yield* SessionRunnerModel.Service
|
||||
const database = yield* Database.Service
|
||||
const title = make({ events, llm, agents, models })
|
||||
const title = make({ events, llm, agents, models, headers: options })
|
||||
return Service.of({
|
||||
generateForFirstPrompt: (session) => title.generateForFirstPrompt(database.db, session),
|
||||
})
|
||||
}),
|
||||
)
|
||||
|
||||
export const node = makeLocationNode({
|
||||
service: Service,
|
||||
layer,
|
||||
deps: [EventV2.node, llmClient, AgentV2.node, SessionRunnerModel.node, Database.node],
|
||||
})
|
||||
export function configured(options?: SessionModelHeaders.Options) {
|
||||
return makeLocationNode({
|
||||
service: Service,
|
||||
layer: layer(options),
|
||||
deps: [EventV2.node, llmClient, AgentV2.node, SessionRunnerModel.node, Database.node],
|
||||
})
|
||||
}
|
||||
|
||||
export const node = configured()
|
||||
|
|
|
|||
|
|
@ -5,7 +5,6 @@ import { ToolFailure } from "@opencode-ai/ai"
|
|||
import { Context, Duration, Effect, Layer, Schema } from "effect"
|
||||
import { HttpClient, HttpClientRequest } from "effect/unstable/http"
|
||||
import { makeLocationNode } from "../effect/app-node"
|
||||
import { truthy } from "../flag/flag"
|
||||
import { InstallationVersion } from "../installation/version"
|
||||
import { PositiveInt } from "../schema"
|
||||
import { PermissionV2 } from "../permission"
|
||||
|
|
@ -74,8 +73,13 @@ export const defaultConfigLayer = Layer.sync(ConfigService, () =>
|
|||
process.env.OPENCODE_WEBSEARCH_PROVIDER === "exa" || process.env.OPENCODE_WEBSEARCH_PROVIDER === "parallel"
|
||||
? process.env.OPENCODE_WEBSEARCH_PROVIDER
|
||||
: undefined,
|
||||
enableExa: truthy("OPENCODE_EXPERIMENTAL") || truthy("OPENCODE_ENABLE_EXA") || truthy("OPENCODE_EXPERIMENTAL_EXA"),
|
||||
enableParallel: truthy("OPENCODE_ENABLE_PARALLEL") || truthy("OPENCODE_EXPERIMENTAL_PARALLEL"),
|
||||
enableExa:
|
||||
["1", "true"].includes(process.env.OPENCODE_EXPERIMENTAL?.toLowerCase() ?? "") ||
|
||||
["1", "true"].includes(process.env.OPENCODE_ENABLE_EXA?.toLowerCase() ?? "") ||
|
||||
["1", "true"].includes(process.env.OPENCODE_EXPERIMENTAL_EXA?.toLowerCase() ?? ""),
|
||||
enableParallel:
|
||||
["1", "true"].includes(process.env.OPENCODE_ENABLE_PARALLEL?.toLowerCase() ?? "") ||
|
||||
["1", "true"].includes(process.env.OPENCODE_EXPERIMENTAL_PARALLEL?.toLowerCase() ?? ""),
|
||||
exaApiKey: process.env.EXA_API_KEY,
|
||||
parallelApiKey: process.env.PARALLEL_API_KEY,
|
||||
}),
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue