From 41886aef808a0805c213d20ec788a5c3c8ec5149 Mon Sep 17 00:00:00 2001 From: Codex Date: Mon, 8 Jun 2026 01:38:50 +0800 Subject: [PATCH] =?UTF-8?q?feat:=20=E5=B0=86=20ofcx-go=20backend=20?= =?UTF-8?q?=E6=94=B6=E6=95=9B=E4=B8=BA=20dsflash-go?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- deploy/deploy.json | 10 ++--- scripts/src/cli.ts | 10 ++--- scripts/src/gitops-render.ts | 4 +- src/common/backend-profiles.ts | 6 +-- src/common/types.ts | 2 +- src/mgr/postgres-store.ts | 38 +++++++++++++++++++ src/mgr/provider-profiles.ts | 30 +++++++++------ src/selftest/cases/00-redaction-postgres.ts | 6 +-- src/selftest/cases/20-runner-k8s-job.ts | 17 ++++++++- src/selftest/cases/30-codex-stdio.ts | 12 +++++- src/selftest/cases/40-secret-render.ts | 8 +++- .../cases/45-provider-profile-management.ts | 4 +- .../cases/60-hwlab-baseline-contract.ts | 3 +- src/selftest/harness.ts | 1 + 14 files changed, 115 insertions(+), 36 deletions(-) diff --git a/deploy/deploy.json b/deploy/deploy.json index 0d5dfa2..bae6582 100644 --- a/deploy/deploy.json +++ b/deploy/deploy.json @@ -58,11 +58,11 @@ "writableCopy": true }, { - "name": "ofcx-go-secret-projection", - "secretRef": { "name": "agentrun-v01-provider-ofcx-go", "keys": ["auth.json", "config.toml"] }, - "projectionPath": "/var/run/agentrun/secrets/ofcx-go-0", - "runtimeCopyPath": "/home/agentrun/.codex-ofcx-go", - "profile": "ofcx-go", + "name": "dsflash-go-secret-projection", + "secretRef": { "name": "agentrun-v01-provider-dsflash-go", "keys": ["auth.json", "config.toml"] }, + "projectionPath": "/var/run/agentrun/secrets/dsflash-go-0", + "runtimeCopyPath": "/home/agentrun/.codex-dsflash-go", + "profile": "dsflash-go", "readOnly": true, "writableCopy": true } diff --git a/scripts/src/cli.ts b/scripts/src/cli.ts index 5f38199..7464fa6 100644 --- a/scripts/src/cli.ts +++ b/scripts/src/cli.ts @@ -757,12 +757,12 @@ function help(): JsonRecord { "runs events --after-seq --limit ", "runs result [--command-id ]", "runs cancel [--reason ]", - "sessions ps [--state default|running|unread|terminal|idle|all] [--profile codex|deepseek|minimax-m3|M3] [--reader-id ]", - "sessions create [sessionId] [--profile codex|deepseek|minimax-m3|M3] [--expires-in-days ]", + "sessions ps [--state default|running|unread|terminal|idle|all] [--profile codex|deepseek|minimax-m3|dsflash-go|M3] [--reader-id ]", + "sessions create [sessionId] [--profile codex|deepseek|minimax-m3|dsflash-go|M3] [--expires-in-days ]", "sessions storage ", "sessions storage --delete", "sessions show [--reader-id ]", - "sessions turn [sessionId] --json-file --prompt-file [--profile minimax-m3|M3] [--runner-json-file ]", + "sessions turn [sessionId] --json-file --prompt-file [--profile minimax-m3|dsflash-go|M3] [--runner-json-file ]", "sessions steer --prompt-file ", "sessions cancel [--reason ]", "sessions trace [--after-seq ] [--limit ] [--run-id ]", @@ -772,7 +772,7 @@ function help(): JsonRecord { "commands show --run-id ", "commands result --run-id ", "commands cancel [--reason ]", - "runner start --run-id [--backend codex|deepseek|minimax-m3]", + "runner start --run-id [--backend codex|deepseek|minimax-m3|dsflash-go]", "runner job --run-id --command-id [--image ] [--runner-manager-url ] [--idempotency-key ]", "runner job --dry-run --run-id --command-id --image ", "runner jobs --run-id [--command-id ]", @@ -786,7 +786,7 @@ function help(): JsonRecord { "queue cancel [--reason ]", "queue dispatch [--json-file ] [--idempotency-key ] [--image ] [--namespace ]", "queue refresh ", - "secrets codex render --dry-run [--profile codex|deepseek|minimax-m3] [--codex-home ] [--namespace agentrun-v01] [--secret-name ]", + "secrets codex render --dry-run [--profile codex|deepseek|minimax-m3|dsflash-go] [--codex-home ] [--namespace agentrun-v01] [--secret-name ]", "provider-profiles list", "provider-profiles show ", "provider-profiles config ", diff --git a/scripts/src/gitops-render.ts b/scripts/src/gitops-render.ts index 0b4e6d6..5c414ca 100644 --- a/scripts/src/gitops-render.ts +++ b/scripts/src/gitops-render.ts @@ -367,7 +367,7 @@ metadata: rules: - apiGroups: [""] resources: ["secrets"] - resourceNames: ["agentrun-v01-provider-codex", "agentrun-v01-provider-deepseek", "agentrun-v01-provider-minimax-m3", "agentrun-v01-provider-ofcx-go"] + resourceNames: ["agentrun-v01-provider-codex", "agentrun-v01-provider-deepseek", "agentrun-v01-provider-minimax-m3", "agentrun-v01-provider-dsflash-go"] verbs: ["get", "patch", "update"] --- apiVersion: rbac.authorization.k8s.io/v1 @@ -400,7 +400,7 @@ metadata: rules: - apiGroups: [""] resources: ["secrets"] - resourceNames: ["agentrun-v01-provider-codex", "agentrun-v01-provider-deepseek", "agentrun-v01-provider-minimax-m3", "agentrun-v01-provider-ofcx-go"] + resourceNames: ["agentrun-v01-provider-codex", "agentrun-v01-provider-deepseek", "agentrun-v01-provider-minimax-m3", "agentrun-v01-provider-dsflash-go"] verbs: ["get"] --- apiVersion: rbac.authorization.k8s.io/v1 diff --git a/src/common/backend-profiles.ts b/src/common/backend-profiles.ts index ab177b0..a7b4909 100644 --- a/src/common/backend-profiles.ts +++ b/src/common/backend-profiles.ts @@ -51,16 +51,16 @@ export const backendProfileSpecs: readonly BackendProfileSpec[] = [ description: "MiniMax M3 OpenAI-compatible profile through Codex app-server stdio", }, { - profile: "ofcx-go", + profile: "dsflash-go", backendKind: "codex-app-server-stdio", protocol: "codex-app-server-jsonrpc-stdio", transport: "stdio", command: "codex app-server --listen stdio://", status: "registered", requiredSecretKeys: ["auth.json", "config.toml"], - defaultSecretName: "agentrun-v01-provider-ofcx-go", + defaultSecretName: "agentrun-v01-provider-dsflash-go", profileIsolation: "profile-scoped-codex-home", - description: "OpenCode Zen Go DeepSeek V4 Flash profile through Moon Bridge", + description: "DeepSeek V4 Flash profile through OpenCode Zen Go Moon Bridge", }, ]; diff --git a/src/common/types.ts b/src/common/types.ts index 96cac4d..f3a3ad2 100644 --- a/src/common/types.ts +++ b/src/common/types.ts @@ -28,7 +28,7 @@ export type FailureKind = export type RunStatus = "pending" | "claimed" | "running" | "completed" | "failed" | "blocked" | "cancelled"; export type CommandState = "pending" | "acknowledged" | "completed" | "failed" | "cancelled"; export type TerminalStatus = "completed" | "failed" | "blocked" | "cancelled"; -export type BackendProfile = "codex" | "deepseek" | "minimax-m3" | "ofcx-go"; +export type BackendProfile = "codex" | "deepseek" | "minimax-m3" | "dsflash-go"; export type QueueTaskState = "pending" | "running" | "completed" | "failed" | "blocked" | "cancelled"; export type SessionExecutionState = "idle" | "running" | "terminal"; export type SessionAttentionState = "active" | "unread" | "read"; diff --git a/src/mgr/postgres-store.ts b/src/mgr/postgres-store.ts index 3bcf5f7..eaccb31 100644 --- a/src/mgr/postgres-store.ts +++ b/src/mgr/postgres-store.ts @@ -137,6 +137,39 @@ ON CONFLICT (profile) DO UPDATE SET updated_at = EXCLUDED.updated_at; `; +const dsflashGoBackendProfileMigrationSql = ` +UPDATE agentrun_runs SET backend_profile = 'dsflash-go' WHERE backend_profile = 'ofcx-go'; +UPDATE agentrun_sessions SET backend_profile = 'dsflash-go' WHERE backend_profile = 'ofcx-go'; +UPDATE agentrun_runners SET backend_profile = 'dsflash-go' WHERE backend_profile = 'ofcx-go'; +UPDATE agentrun_queue_tasks SET backend_profile = 'dsflash-go' WHERE backend_profile = 'ofcx-go'; +UPDATE agentrun_runs +SET execution_policy = replace(replace(replace(execution_policy::text, + '"profile": "ofcx-go"', + '"profile": "dsflash-go"'), + 'agentrun-v01-provider-ofcx-go', + 'agentrun-v01-provider-dsflash-go'), + '/home/agentrun/.codex-ofcx-go', + '/home/agentrun/.codex-dsflash-go')::jsonb +WHERE execution_policy::text LIKE '%ofcx-go%'; +UPDATE agentrun_queue_tasks +SET execution_policy = replace(replace(replace(execution_policy::text, + '"profile": "ofcx-go"', + '"profile": "dsflash-go"'), + 'agentrun-v01-provider-ofcx-go', + 'agentrun-v01-provider-dsflash-go'), + '/home/agentrun/.codex-ofcx-go', + '/home/agentrun/.codex-dsflash-go')::jsonb +WHERE execution_policy IS NOT NULL AND execution_policy::text LIKE '%ofcx-go%'; +DELETE FROM agentrun_backends WHERE profile = 'ofcx-go'; +INSERT INTO agentrun_backends (profile, capabilities, capacity, health, updated_at) +VALUES ${backendCapabilitiesSqlValues(["dsflash-go"])} +ON CONFLICT (profile) DO UPDATE SET + capabilities = EXCLUDED.capabilities, + capacity = EXCLUDED.capacity, + health = EXCLUDED.health, + updated_at = EXCLUDED.updated_at; +`; + const sessionControlMigrationSql = ` ALTER TABLE agentrun_sessions ADD COLUMN IF NOT EXISTS version bigint NOT NULL DEFAULT 1; ALTER TABLE agentrun_sessions ADD COLUMN IF NOT EXISTS execution_state text NOT NULL DEFAULT 'idle'; @@ -322,6 +355,11 @@ const postgresMigrations: MigrationDefinition[] = [ checksum: checksumSql(sessionStateStorageMigrationSql), sql: sessionStateStorageMigrationSql, }, + { + id: "008_v01_dsflash_go_backend_profile", + checksum: checksumSql(dsflashGoBackendProfileMigrationSql), + sql: dsflashGoBackendProfileMigrationSql, + }, ]; export function postgresMigrationContract(): JsonRecord { diff --git a/src/mgr/provider-profiles.ts b/src/mgr/provider-profiles.ts index 56126da..474358d 100644 --- a/src/mgr/provider-profiles.ts +++ b/src/mgr/provider-profiles.ts @@ -122,7 +122,7 @@ export async function setProviderProfileConfig(profileValue: string, body: unkno configHashSuffix: shortHash(configToml), updatedAt: objectPath(applied, ["metadata", "annotations", `${credentialAnnotationPrefix}-updated-at`]) ?? new Date().toISOString(), delegatedBy, - requiresExternalBridgeUpdate: profile === "deepseek", + requiresExternalBridgeUpdate: profile === "deepseek" || profile === "dsflash-go", configTomlPrinted: false, credentialValuesPrinted: false, valuesPrinted: false, @@ -180,7 +180,7 @@ export async function setProviderProfileCredential(profileValue: string, body: u updatedAt: objectPath(applied, ["metadata", "annotations", `${credentialAnnotationPrefix}-updated-at`]) ?? new Date().toISOString(), configSummary: rendered.config.configSummary, delegatedBy, - requiresExternalBridgeUpdate: profile === "deepseek", + requiresExternalBridgeUpdate: profile === "deepseek" || profile === "dsflash-go", valuesPrinted: false, pollCommands: { show: `./scripts/agentrun provider-profiles show ${profile}`, @@ -297,14 +297,15 @@ function authPayload(apiKey: string): JsonRecord { } function renderConfigToml(config: ProfileConfig): string { + const { contextWindow, autoCompactTokenLimit } = contextWindowSettings(config.model); return [ `model_provider = ${tomlString(config.providerName)}`, `model = ${tomlString(config.model)}`, `review_model = ${tomlString(config.model)}`, "disable_response_storage = true", "network_access = \"enabled\"", - "model_context_window = 128000", - "model_auto_compact_token_limit = 110000", + `model_context_window = ${contextWindow}`, + `model_auto_compact_token_limit = ${autoCompactTokenLimit}`, "approvals_reviewer = \"user\"", "", `[model_providers.${config.providerName}]`, @@ -368,8 +369,8 @@ async function existingConfigToml(profile: BackendProfile, options: ProviderProf function existingConfigAllowed(profile: BackendProfile, configToml: string): boolean { if (configToml.trim().length === 0) return false; - if (profile === "deepseek" && configToml.includes("hyueapi.com")) return false; - if (profile === "deepseek" && !configToml.includes("hwlab-deepseek-proxy.hwlab-v02.svc.cluster.local")) return false; + if ((profile === "deepseek" || profile === "dsflash-go") && configToml.includes("hyueapi.com")) return false; + if ((profile === "deepseek" || profile === "dsflash-go") && !configToml.includes("hwlab-deepseek-proxy.hwlab-v02.svc.cluster.local")) return false; return true; } @@ -414,7 +415,7 @@ function defaultConfig(profile: BackendProfile): ProfileConfig { displayName: "OpenAI", }; } - if (profile === "ofcx-go") { + if (profile === "dsflash-go") { return { model: "deepseek-v4-flash", providerName: "opencode", @@ -451,14 +452,21 @@ function validateBaseUrl(profile: BackendProfile, value: string): void { } catch { throw new AgentRunError("schema-invalid", "config.baseUrl must be a valid URL", { httpStatus: 400 }); } - if (profile === "deepseek" && url.hostname === "hyueapi.com") { - throw new AgentRunError("tenant-policy-denied", "deepseek profile must use HWLAB Moon Bridge, not hyueapi.com", { httpStatus: 403 }); + if ((profile === "deepseek" || profile === "dsflash-go") && url.hostname === "hyueapi.com") { + throw new AgentRunError("tenant-policy-denied", `${profile} profile must use HWLAB Moon Bridge, not hyueapi.com`, { httpStatus: 403 }); } - if (profile === "deepseek" && url.hostname !== "hwlab-deepseek-proxy.hwlab-v02.svc.cluster.local") { - throw new AgentRunError("tenant-policy-denied", "deepseek profile baseUrl must point to HWLAB v0.2 Moon Bridge", { httpStatus: 403 }); + if ((profile === "deepseek" || profile === "dsflash-go") && url.hostname !== "hwlab-deepseek-proxy.hwlab-v02.svc.cluster.local") { + throw new AgentRunError("tenant-policy-denied", `${profile} profile baseUrl must point to HWLAB v0.2 Moon Bridge`, { httpStatus: 403 }); } } +function contextWindowSettings(model: string): { contextWindow: number; autoCompactTokenLimit: number } { + if (model === "deepseek-v4-pro" || model === "deepseek-v4-flash") { + return { contextWindow: 1_000_000, autoCompactTokenLimit: 900_000 }; + } + return { contextWindow: 200_000, autoCompactTokenLimit: 180_000 }; +} + function validationExecutionPolicy(profile: BackendProfile, namespace: string): ExecutionPolicy { const spec = requiredSpec(profile); return { diff --git a/src/selftest/cases/00-redaction-postgres.ts b/src/selftest/cases/00-redaction-postgres.ts index 4388d83..0c9f6ff 100644 --- a/src/selftest/cases/00-redaction-postgres.ts +++ b/src/selftest/cases/00-redaction-postgres.ts @@ -13,9 +13,9 @@ const selfTest: SelfTestCase = async () => { (error) => error instanceof AgentRunError && error.failureKind === "infra-failed" && error.message.includes("DATABASE_URL is required"), ); const postgresContract = postgresMigrationContract(); - assert.equal(postgresContract.latestMigrationId, "007_v01_session_state_storage"); - assert.equal((postgresContract.migrationIds as string[]).includes("007_v01_session_state_storage"), true); - assert.ok(typeof (postgresContract.checksums as Record)["007_v01_session_state_storage"] === "string" && (postgresContract.checksums as Record)["007_v01_session_state_storage"].length > 0); + assert.equal(postgresContract.latestMigrationId, "008_v01_dsflash_go_backend_profile"); + assert.equal((postgresContract.migrationIds as string[]).includes("008_v01_dsflash_go_backend_profile"), true); + assert.ok(typeof (postgresContract.checksums as Record)["008_v01_dsflash_go_backend_profile"] === "string" && (postgresContract.checksums as Record)["008_v01_dsflash_go_backend_profile"].length > 0); assert.equal((postgresContract.checksums as Record)["002_v01_backend_profiles"], "928b5c490cc4539cb64ecef34784557601b2724fa2870570f16a53576804e49c"); assert.ok(Array.isArray(postgresContract.requiredTables)); assert.ok(postgresContract.requiredTables.includes("agentrun_schema_migrations")); diff --git a/src/selftest/cases/20-runner-k8s-job.ts b/src/selftest/cases/20-runner-k8s-job.ts index 811acb2..48530ad 100644 --- a/src/selftest/cases/20-runner-k8s-job.ts +++ b/src/selftest/cases/20-runner-k8s-job.ts @@ -86,6 +86,21 @@ const selfTest: SelfTestCase = async (context) => { assertRunnerJobDoesNotMountProfile(minimaxRendered.manifest as JsonRecord, "deepseek-0"); assertNoSecretLeak(minimaxRendered); + const dsflashGoItem = await createRunWithCommand(client, { ...context, backendProfile: "dsflash-go" }, "dsflash-go job smoke", "selftest-dsflash-go-job-render", 15_000); + const dsflashGoRendered = renderRunnerJobDryRun({ + run: await client.get(`/api/v1/runs/${dsflashGoItem.runId}`) as RunRecord, + commandId: dsflashGoItem.commandId, + managerUrl: server.baseUrl, + image: "127.0.0.1:5000/agentrun/agentrun-mgr@sha256:1111111111111111111111111111111111111111111111111111111111111111", + attemptId: "attempt_selftest_dsflash_go", + sourceCommit: "self-test", + }); + assertRunnerJobUsesWritableCodexHome(dsflashGoRendered.manifest as JsonRecord, context.deepseekHome, "dsflash-go-0", "/var/run/agentrun/secrets/dsflash-go-0"); + assertRunnerJobDoesNotMountProfile(dsflashGoRendered.manifest as JsonRecord, "codex-0"); + assertRunnerJobDoesNotMountProfile(dsflashGoRendered.manifest as JsonRecord, "deepseek-0"); + assertRunnerJobDoesNotMountProfile(dsflashGoRendered.manifest as JsonRecord, "minimax-m3-0"); + assertNoSecretLeak(dsflashGoRendered); + const fakeKubectl = path.join(context.tmp, "fake-kubectl.js"); const createdManifest = path.join(context.tmp, "created-runner-job.json"); await writeFile(fakeKubectl, `#!/usr/bin/env bun @@ -193,7 +208,7 @@ console.log(JSON.stringify({ apiVersion: manifest.apiVersion, kind: manifest.kin assert.equal(envMap.get("AGENTRUN_SESSION_PVC_NAMESPACE"), "agentrun-v01"); assert.equal(envMap.get("AGENTRUN_SESSION_PVC_MOUNT_PATH"), "/home/agentrun/.codex-codex/sessions"); assert.equal(envMap.get("AGENTRUN_CODEX_ROLLOUT_SUBDIR"), "sessions"); - return { name: "runner-k8s-job", tests: ["runner-k8s-job-dry-run", "runner-k8s-job-deepseek-profile-dry-run", "runner-k8s-job-minimax-m3-profile-dry-run", "runner-k8s-job-create-api", "runner-k8s-job-retention-ttl", "runner-job-transient-env", "runner-job-tool-credential-env", "runner-job-unidesk-ssh-tool-credential-env", "runner-job-unidesk-ssh-transient-env-denied", "runner-k8s-job-session-pvc-volume-and-env"] }; + return { name: "runner-k8s-job", tests: ["runner-k8s-job-dry-run", "runner-k8s-job-deepseek-profile-dry-run", "runner-k8s-job-minimax-m3-profile-dry-run", "runner-k8s-job-dsflash-go-profile-dry-run", "runner-k8s-job-create-api", "runner-k8s-job-retention-ttl", "runner-job-transient-env", "runner-job-tool-credential-env", "runner-job-unidesk-ssh-tool-credential-env", "runner-job-unidesk-ssh-transient-env-denied", "runner-k8s-job-session-pvc-volume-and-env"] }; } finally { await new Promise((resolve) => server.server.close(() => resolve())); } diff --git a/src/selftest/cases/30-codex-stdio.ts b/src/selftest/cases/30-codex-stdio.ts index 86df720..0ea002d 100644 --- a/src/selftest/cases/30-codex-stdio.ts +++ b/src/selftest/cases/30-codex-stdio.ts @@ -56,6 +56,16 @@ const selfTest: SelfTestCase = async (context) => { assert.ok(minimaxM3Events.items?.some((event) => event.type === "backend_status" && JSON.stringify(event.payload).includes("minimax-m3")), "minimax-m3 backend_status should include profile metadata"); assertNoSecretLeak(minimaxM3Events); + const dsflashGoHome = path.join(context.tmp, "runtime-dsflash-go-home"); + const dsflashGo = await createRunWithCommand(client, { ...context, backendProfile: "dsflash-go" }, "hello dsflash-go", "selftest-dsflash-go-turn", 15_000); + const dsflashGoResult = await runOnce({ managerUrl: server.baseUrl, runId: dsflashGo.runId, backendProfile: "dsflash-go", codexCommand: context.fakeCodexCommand, codexArgs: context.fakeCodexArgs, codexHome: dsflashGoHome, env: { CODEX_HOME: dsflashGoHome, AGENTRUN_CODEX_SECRET_HOME: context.deepseekHome }, oneShot: true }); + assert.equal(dsflashGoResult.terminalStatus, "completed"); + await access(path.join(dsflashGoHome, "auth.json")); + await access(path.join(dsflashGoHome, "config.toml")); + const dsflashGoEvents = await client.get(`/api/v1/runs/${dsflashGo.runId}/events?afterSeq=0&limit=100`) as { items?: Array<{ type: string; payload: unknown }> }; + assert.ok(dsflashGoEvents.items?.some((event) => event.type === "backend_status" && JSON.stringify(event.payload).includes("dsflash-go")), "dsflash-go backend_status should include profile metadata"); + assertNoSecretLeak(dsflashGoEvents); + await assert.rejects( () => createRunWithCommand(client, { ...context, backendProfile: "deepseek", includeOnlyProfile: "codex" }, "missing deepseek", "selftest-deepseek-missing-secret", 15_000), (error) => error instanceof Error && error.message.includes("requires a matching provider credential"), @@ -217,7 +227,7 @@ const selfTest: SelfTestCase = async (context) => { await runSessionStorageSubdirCase({ client, managerUrl: server.baseUrl, context }); await runSessionStorageNoSecretLeakCase({ client, managerUrl: server.baseUrl, context }); - return { name: "codex-stdio", tests: ["runner-lease-heartbeat", "runner-lease-conflict-recovery", "codex-stdio-fake-turn", "codex-stdio-projected-writable-home", "codex-stdio-deepseek-profile-fake-turn", "codex-stdio-minimax-m3-profile-fake-turn", "codex-stdio-deepseek-missing-secret-no-fallback", "codex-stdio-minimax-m3-missing-secret-no-fallback", "codex-stdio-config-model-authoritative", "codex-stdio-explicit-model-forwarded", "codex-stdio-final-agent-message-only", "codex-stdio-web-search-progress", "codex-stdio-stale-thread-resume-failed", "codex-stdio-live-tool-events", "codex-stdio-noisy-reasoning-suppression", "codex-stdio-missing-turn-result", "codex-stdio-provider-auth-failed", "codex-stdio-provider-rate-limited", "codex-stdio-provider-invalid-tool-call", "codex-stdio-provider-503-rpc-error", "codex-stdio-provider-503-terminal", "codex-stdio-provider-503-retry-event", "codex-stdio-invalid-json", "codex-stdio-timeout", "codex-stdio-idle-timeout-progress-refresh", "codex-stdio-command-failure-keeps-run-open", "codex-stdio-secret-unavailable", "codex-stdio-spawn-failure"] }; + return { name: "codex-stdio", tests: ["runner-lease-heartbeat", "runner-lease-conflict-recovery", "codex-stdio-fake-turn", "codex-stdio-projected-writable-home", "codex-stdio-deepseek-profile-fake-turn", "codex-stdio-dsflash-go-profile-fake-turn", "codex-stdio-minimax-m3-profile-fake-turn", "codex-stdio-deepseek-missing-secret-no-fallback", "codex-stdio-minimax-m3-missing-secret-no-fallback", "codex-stdio-config-model-authoritative", "codex-stdio-explicit-model-forwarded", "codex-stdio-final-agent-message-only", "codex-stdio-web-search-progress", "codex-stdio-stale-thread-resume-failed", "codex-stdio-live-tool-events", "codex-stdio-noisy-reasoning-suppression", "codex-stdio-missing-turn-result", "codex-stdio-provider-auth-failed", "codex-stdio-provider-rate-limited", "codex-stdio-provider-invalid-tool-call", "codex-stdio-provider-503-rpc-error", "codex-stdio-provider-503-terminal", "codex-stdio-provider-503-retry-event", "codex-stdio-invalid-json", "codex-stdio-timeout", "codex-stdio-idle-timeout-progress-refresh", "codex-stdio-command-failure-keeps-run-open", "codex-stdio-secret-unavailable", "codex-stdio-spawn-failure"] }; } finally { await new Promise((resolve) => server.server.close(() => resolve())); } diff --git a/src/selftest/cases/40-secret-render.ts b/src/selftest/cases/40-secret-render.ts index 5c7fa24..929c319 100644 --- a/src/selftest/cases/40-secret-render.ts +++ b/src/selftest/cases/40-secret-render.ts @@ -32,6 +32,12 @@ const selfTest: SelfTestCase = async (context) => { assert.equal(JSON.stringify(minimaxM3SecretPlan).includes("MiniMax-M3"), false); assert.equal(JSON.stringify(minimaxM3SecretPlan).includes("api.minimaxi.com"), false); + const dsflashGoSecretPlan = await renderCodexProviderSecretPlan({ profile: "dsflash-go", codexHome: context.deepseekHome, dryRun: true }); + assert.equal(dsflashGoSecretPlan.secretName, "agentrun-v01-provider-dsflash-go"); + assert.equal(dsflashGoSecretPlan.profile, "dsflash-go"); + assert.equal(JSON.stringify(dsflashGoSecretPlan).includes("test-token-material-deepseek"), false); + assert.equal(JSON.stringify(dsflashGoSecretPlan).includes("deepseek-test"), false); + await assert.rejects( () => renderCodexProviderSecretPlan({ codexHome: path.join(context.tmp, "missing-codex-home"), dryRun: true }), (error) => error instanceof AgentRunError && error.failureKind === "secret-unavailable", @@ -56,7 +62,7 @@ const selfTest: SelfTestCase = async (context) => { (error) => error instanceof AgentRunError && error.failureKind === "schema-invalid", ); - return { name: "secret-render", tests: ["codex-secret-dry-run", "deepseek-secret-dry-run", "minimax-m3-secret-dry-run"] }; + return { name: "secret-render", tests: ["codex-secret-dry-run", "deepseek-secret-dry-run", "minimax-m3-secret-dry-run", "dsflash-go-secret-dry-run"] }; }; export default selfTest; diff --git a/src/selftest/cases/45-provider-profile-management.ts b/src/selftest/cases/45-provider-profile-management.ts index bf3162f..e4a3486 100644 --- a/src/selftest/cases/45-provider-profile-management.ts +++ b/src/selftest/cases/45-provider-profile-management.ts @@ -13,8 +13,8 @@ const selfTest: SelfTestCase = async (context) => { const gitopsRenderer = await readFile(path.join(context.root, "scripts/src/gitops-render.ts"), "utf8"); assert.equal(gitopsRenderer.includes("agentrun-v01-mgr-provider-secret-manager"), true); assert.equal(gitopsRenderer.includes('verbs: ["get", "patch", "update"]'), true); - assert.equal(gitopsRenderer.includes('resourceNames: ["agentrun-v01-provider-codex", "agentrun-v01-provider-deepseek", "agentrun-v01-provider-minimax-m3", "agentrun-v01-provider-ofcx-go"]'), true); - for (const profile of ["codex", "deepseek", "minimax-m3", "ofcx-go"]) { + assert.equal(gitopsRenderer.includes('resourceNames: ["agentrun-v01-provider-codex", "agentrun-v01-provider-deepseek", "agentrun-v01-provider-minimax-m3", "agentrun-v01-provider-dsflash-go"]'), true); + for (const profile of ["codex", "deepseek", "minimax-m3", "dsflash-go"]) { assert.equal(gitopsRenderer.includes(`agentrun-v01-provider-${profile}`), true); } diff --git a/src/selftest/cases/60-hwlab-baseline-contract.ts b/src/selftest/cases/60-hwlab-baseline-contract.ts index d30bd72..17072fa 100644 --- a/src/selftest/cases/60-hwlab-baseline-contract.ts +++ b/src/selftest/cases/60-hwlab-baseline-contract.ts @@ -56,8 +56,9 @@ console.log(JSON.stringify({ apiVersion: manifest.apiVersion, kind: manifest.kin async function assertBackendPreflight(client: ManagerClient): Promise { const response = await client.get("/api/v1/backends") as { items?: JsonRecord[] }; const items = response.items ?? []; - assert.ok(items.length >= 3, "codex/deepseek/minimax-m3 backend capabilities should be visible"); + assert.ok(items.length >= 4, "codex/deepseek/minimax-m3/dsflash-go backend capabilities should be visible"); assert.ok(items.some((item) => item.profile === "minimax-m3"), "minimax-m3 backend capability should be visible"); + assert.ok(items.some((item) => item.profile === "dsflash-go"), "dsflash-go backend capability should be visible"); for (const item of items) { const preflight = item.preflight as JsonRecord; const defaultSecretRef = item.defaultSecretRef as JsonRecord; diff --git a/src/selftest/harness.ts b/src/selftest/harness.ts index a927756..573edf1 100644 --- a/src/selftest/harness.ts +++ b/src/selftest/harness.ts @@ -109,6 +109,7 @@ export function assertNoSecretLeak(value: unknown): void { export function profileSecretHome(context: Pick & Partial>, profile: BackendProfile): string { if (profile === "deepseek") return context.deepseekHome ?? context.codexHome; + if (profile === "dsflash-go") return context.deepseekHome ?? context.codexHome; if (profile === "minimax-m3") return context.minimaxM3Home ?? context.codexHome; return context.codexHome; }