feat: configure opencode dsflash-go provider

Refs #2268
This commit is contained in:
UniDesk Codex
2026-06-30 06:17:40 +08:00
parent c1665a0318
commit 2f1d34b36a
4 changed files with 166 additions and 18 deletions
+104 -18
View File
@@ -415,6 +415,10 @@ function requiredAccessConfigString(value, label) {
return text;
}
function optionalObject(value) {
return value && typeof value === "object" && !Array.isArray(value) ? value : {};
}
async function gitValue(args) {
const result = await execFileAsync("git", args, { cwd: repoRoot, timeout: 10000, maxBuffer: 1024 * 1024 });
return result.stdout.trim();
@@ -987,6 +991,13 @@ function secretNameForProfile(secretName, profile) {
return secretName;
}
function secretRefObjectForProfile(secretRef, profile) {
const ref = configString(secretRef);
const slashIndex = ref.indexOf("/");
assert.ok(slashIndex > 0 && slashIndex < ref.length - 1, `secretRef ${JSON.stringify(secretRef)} must be name/key`);
return { name: secretNameForProfile(ref.slice(0, slashIndex), profile), key: ref.slice(slashIndex + 1), optional: true };
}
function rewritePodSecretRefs(podSpec, profile) {
if (!podSpec || !isRuntimeLane(profile)) return;
for (const volume of podSpec.volumes ?? []) {
@@ -996,20 +1007,7 @@ function rewritePodSecretRefs(podSpec, profile) {
function deployEnvEntry(name, value, namespace, profile = "dev") {
if (typeof value === "string" && value.startsWith("secretRef:")) {
const ref = value.slice("secretRef:".length);
const slashIndex = ref.indexOf("/");
if (slashIndex > 0 && slashIndex < ref.length - 1) {
return {
name,
valueFrom: {
secretKeyRef: {
name: secretNameForProfile(ref.slice(0, slashIndex), profile),
key: ref.slice(slashIndex + 1),
optional: true
}
}
};
}
return { name, valueFrom: { secretKeyRef: secretRefObjectForProfile(value.slice("secretRef:".length), profile) } };
}
return { name, value: namespaceScopedHost(value, namespace) };
}
@@ -5638,7 +5636,81 @@ function secretPlaneIssueLabelValue(issueRef) {
return label;
}
function opencodeServerManifest({ profile = "v03", source }) {
function opencodeRuntimeConfigForProfile(deploy, profile) {
const config = optionalObject(deploy?.lanes?.[profile]?.opencode);
const providerProfile = configString(config.providerProfile) || "dsflash-go";
const providerId = configString(config.providerId) || providerProfile;
const model = configString(config.model) || "deepseek-v4-flash";
const smallModel = configString(config.smallModel) || model;
const apiKeyEnv = configString(config.apiKeyEnv) || opencodeApiKeyEnvName(providerId);
const contextLimit = opencodePositiveInteger(config.contextLimit, 1000000, `deploy.lanes.${profile}.opencode.contextLimit`);
const outputLimit = opencodePositiveInteger(config.outputLimit, 384000, `deploy.lanes.${profile}.opencode.outputLimit`);
return {
providerProfile,
providerId,
displayName: configString(config.displayName) || `AgentRun ${providerProfile}`,
model,
smallModel,
baseURL: configString(config.baseURL) || "https://opencode.ai/zen/go/v1",
npm: configString(config.npm) || "@ai-sdk/openai-compatible",
apiKeyEnv,
apiKeySecretRef: configString(config.apiKeySecretRef) || "hwlab-code-agent-provider/opencode-api-key",
contextLimit,
outputLimit,
agentrunSecretNamespace: configString(config.agentrunSecretNamespace) || "agentrun-v02",
agentrunSecretName: configString(config.agentrunSecretName) || `agentrun-v01-provider-${providerProfile}`,
agentrunSecretKeys: Array.isArray(config.agentrunSecretKeys) && config.agentrunSecretKeys.length > 0
? config.agentrunSecretKeys.map(configString).filter(Boolean)
: ["auth.json", "config.toml", "model-catalog.json"]
};
}
function opencodePositiveInteger(value, fallback, label) {
if (value === undefined || value === null) return fallback;
assert.ok(Number.isInteger(value) && value > 0, `${label} must be a positive integer`);
return value;
}
function opencodeApiKeyEnvName(providerId) {
const normalized = String(providerId || "provider").toUpperCase().replace(/[^A-Z0-9]+/gu, "_").replace(/^_+|_+$/gu, "");
return `OPENCODE_${normalized || "PROVIDER"}_API_KEY`;
}
function opencodeConfigContent(config) {
return JSON.stringify({
$schema: "https://opencode.ai/config.json",
autoupdate: false,
share: "disabled",
model: `${config.providerId}/${config.model}`,
small_model: `${config.providerId}/${config.smallModel}`,
provider: {
[config.providerId]: {
npm: config.npm,
name: config.displayName,
options: {
baseURL: config.baseURL,
apiKey: `{env:${config.apiKeyEnv}}`,
timeout: 600000,
headerTimeout: 600000,
chunkTimeout: 300000
},
models: {
[config.model]: {
name: config.model,
reasoning: true,
tool_call: true,
limit: {
context: config.contextLimit,
output: config.outputLimit
}
}
}
}
}
});
}
function opencodeServerManifest({ profile = "v03", source, deploy = null }) {
assert.ok(isRuntimeLane(profile), `opencode-server profile must be a runtime lane, got ${profile}`);
const namespace = namespaceNameForProfile(profile);
const name = "opencode-server";
@@ -5655,9 +5727,22 @@ function opencodeServerManifest({ profile = "v03", source }) {
"hwlab.pikastech.local/service-id": name,
"hwlab.pikastech.local/source-commit": source.full
};
const annotations = { "hwlab.pikastech.local/rendered-by": "scripts/gitops-render.mjs" };
const opencodeConfig = opencodeRuntimeConfigForProfile(deploy, profile);
const configContent = opencodeConfigContent(opencodeConfig);
const configSha256 = createHash("sha256").update(configContent).digest("hex");
const apiKeySecretRef = secretRefObjectForProfile(opencodeConfig.apiKeySecretRef, profile);
const annotations = {
"hwlab.pikastech.local/rendered-by": "scripts/gitops-render.mjs",
"hwlab.pikastech.local/opencode-provider-profile": opencodeConfig.providerProfile,
"hwlab.pikastech.local/opencode-provider-id": opencodeConfig.providerId,
"hwlab.pikastech.local/opencode-model": opencodeConfig.model,
"hwlab.pikastech.local/opencode-config-sha256": configSha256,
"hwlab.pikastech.local/opencode-api-key-secret-ref": `${apiKeySecretRef.name}/${apiKeySecretRef.key}`,
"hwlab.pikastech.local/agentrun-provider-secret-ref": `${opencodeConfig.agentrunSecretNamespace}/${opencodeConfig.agentrunSecretName}`,
"hwlab.pikastech.local/agentrun-provider-secret-keys": opencodeConfig.agentrunSecretKeys.join(","),
"hwlab.pikastech.local/values-printed": "false"
};
const authSecretName = secretNameForProfile("hwlab-opencode-server-auth", profile);
const configContent = JSON.stringify({ autoupdate: false, share: "disabled" });
return {
apiVersion: "v1",
kind: "List",
@@ -5711,6 +5796,7 @@ function opencodeServerManifest({ profile = "v03", source }) {
{ name: "XDG_CONFIG_HOME", value: "/workspace/.config" },
{ name: "XDG_DATA_HOME", value: "/workspace/.local/share" },
{ name: "OPENCODE_CONFIG_CONTENT", value: configContent },
{ name: opencodeConfig.apiKeyEnv, valueFrom: { secretKeyRef: apiKeySecretRef } },
{ name: "OPENCODE_SERVER_USERNAME", valueFrom: { secretKeyRef: { name: authSecretName, key: "username" } } },
{ name: "OPENCODE_SERVER_PASSWORD", valueFrom: { secretKeyRef: { name: authSecretName, key: "password" } } }
],
@@ -5905,7 +5991,7 @@ async function plannedFiles(args) {
if (workbenchRedis) putJson(`${runtimePath}/workbench-redis.yaml`, workbenchRuntimeRedisManifest({ profile, config: workbenchRedis, source }));
if (isRuntimeLane(profile)) putJson(`${runtimePath}/openfga.yaml`, v02OpenFgaManifest({ profile, source }));
if (isRuntimeLane(profile)) putJson(`${runtimePath}/observability.yaml`, observabilityManifest({ deploy, profile, namespace, labels: profileLabels, annotations, metricsSidecarScript }));
if (isRuntimeLane(profile)) putJson(`${runtimePath}/opencode.yaml`, opencodeServerManifest({ profile, source }));
if (isRuntimeLane(profile)) putJson(`${runtimePath}/opencode.yaml`, opencodeServerManifest({ profile, source, deploy }));
if (includeDeviceAgent) putJson(`${runtimePath}/device-agent-71-freq.yaml`, deviceAgent71FreqManifest({ profile, source, registryPrefix: args.registryPrefix, catalog: artifactCatalog, useDeployImages: args.useDeployImages }));
putJson(`${runtimePath}/node-frpc.yaml`, nodeFrpcManifest({ profile, source }));
}