feat: 将 ofcx-go backend 收敛为 dsflash-go
This commit is contained in:
+5
-5
@@ -58,11 +58,11 @@
|
|||||||
"writableCopy": true
|
"writableCopy": true
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "ofcx-go-secret-projection",
|
"name": "dsflash-go-secret-projection",
|
||||||
"secretRef": { "name": "agentrun-v01-provider-ofcx-go", "keys": ["auth.json", "config.toml"] },
|
"secretRef": { "name": "agentrun-v01-provider-dsflash-go", "keys": ["auth.json", "config.toml"] },
|
||||||
"projectionPath": "/var/run/agentrun/secrets/ofcx-go-0",
|
"projectionPath": "/var/run/agentrun/secrets/dsflash-go-0",
|
||||||
"runtimeCopyPath": "/home/agentrun/.codex-ofcx-go",
|
"runtimeCopyPath": "/home/agentrun/.codex-dsflash-go",
|
||||||
"profile": "ofcx-go",
|
"profile": "dsflash-go",
|
||||||
"readOnly": true,
|
"readOnly": true,
|
||||||
"writableCopy": true
|
"writableCopy": true
|
||||||
}
|
}
|
||||||
|
|||||||
+5
-5
@@ -757,12 +757,12 @@ function help(): JsonRecord {
|
|||||||
"runs events <runId> --after-seq <n> --limit <n>",
|
"runs events <runId> --after-seq <n> --limit <n>",
|
||||||
"runs result <runId> [--command-id <commandId>]",
|
"runs result <runId> [--command-id <commandId>]",
|
||||||
"runs cancel <runId> [--reason <text>]",
|
"runs cancel <runId> [--reason <text>]",
|
||||||
"sessions ps [--state default|running|unread|terminal|idle|all] [--profile codex|deepseek|minimax-m3|M3] [--reader-id <reader>]",
|
"sessions ps [--state default|running|unread|terminal|idle|all] [--profile codex|deepseek|minimax-m3|dsflash-go|M3] [--reader-id <reader>]",
|
||||||
"sessions create [sessionId] [--profile codex|deepseek|minimax-m3|M3] [--expires-in-days <n>]",
|
"sessions create [sessionId] [--profile codex|deepseek|minimax-m3|dsflash-go|M3] [--expires-in-days <n>]",
|
||||||
"sessions storage <sessionId>",
|
"sessions storage <sessionId>",
|
||||||
"sessions storage <sessionId> --delete",
|
"sessions storage <sessionId> --delete",
|
||||||
"sessions show <sessionId> [--reader-id <reader>]",
|
"sessions show <sessionId> [--reader-id <reader>]",
|
||||||
"sessions turn [sessionId] --json-file <run-base.json> --prompt-file <file> [--profile minimax-m3|M3] [--runner-json-file <job.json>]",
|
"sessions turn [sessionId] --json-file <run-base.json> --prompt-file <file> [--profile minimax-m3|dsflash-go|M3] [--runner-json-file <job.json>]",
|
||||||
"sessions steer <sessionId> --prompt-file <file>",
|
"sessions steer <sessionId> --prompt-file <file>",
|
||||||
"sessions cancel <sessionId> [--reason <text>]",
|
"sessions cancel <sessionId> [--reason <text>]",
|
||||||
"sessions trace <sessionId> [--after-seq <n>] [--limit <n>] [--run-id <runId>]",
|
"sessions trace <sessionId> [--after-seq <n>] [--limit <n>] [--run-id <runId>]",
|
||||||
@@ -772,7 +772,7 @@ function help(): JsonRecord {
|
|||||||
"commands show <commandId> --run-id <runId>",
|
"commands show <commandId> --run-id <runId>",
|
||||||
"commands result <commandId> --run-id <runId>",
|
"commands result <commandId> --run-id <runId>",
|
||||||
"commands cancel <commandId> [--reason <text>]",
|
"commands cancel <commandId> [--reason <text>]",
|
||||||
"runner start --run-id <runId> [--backend codex|deepseek|minimax-m3]",
|
"runner start --run-id <runId> [--backend codex|deepseek|minimax-m3|dsflash-go]",
|
||||||
"runner job --run-id <runId> --command-id <commandId> [--image <image>] [--runner-manager-url <url>] [--idempotency-key <key>]",
|
"runner job --run-id <runId> --command-id <commandId> [--image <image>] [--runner-manager-url <url>] [--idempotency-key <key>]",
|
||||||
"runner job --dry-run --run-id <runId> --command-id <commandId> --image <image>",
|
"runner job --dry-run --run-id <runId> --command-id <commandId> --image <image>",
|
||||||
"runner jobs --run-id <runId> [--command-id <commandId>]",
|
"runner jobs --run-id <runId> [--command-id <commandId>]",
|
||||||
@@ -786,7 +786,7 @@ function help(): JsonRecord {
|
|||||||
"queue cancel <taskId> [--reason <text>]",
|
"queue cancel <taskId> [--reason <text>]",
|
||||||
"queue dispatch <taskId> [--json-file <dispatch.json>] [--idempotency-key <key>] [--image <image>] [--namespace <namespace>]",
|
"queue dispatch <taskId> [--json-file <dispatch.json>] [--idempotency-key <key>] [--image <image>] [--namespace <namespace>]",
|
||||||
"queue refresh <taskId>",
|
"queue refresh <taskId>",
|
||||||
"secrets codex render --dry-run [--profile codex|deepseek|minimax-m3] [--codex-home <dir>] [--namespace agentrun-v01] [--secret-name <name>]",
|
"secrets codex render --dry-run [--profile codex|deepseek|minimax-m3|dsflash-go] [--codex-home <dir>] [--namespace agentrun-v01] [--secret-name <name>]",
|
||||||
"provider-profiles list",
|
"provider-profiles list",
|
||||||
"provider-profiles show <profile>",
|
"provider-profiles show <profile>",
|
||||||
"provider-profiles config <profile>",
|
"provider-profiles config <profile>",
|
||||||
|
|||||||
@@ -367,7 +367,7 @@ metadata:
|
|||||||
rules:
|
rules:
|
||||||
- apiGroups: [""]
|
- apiGroups: [""]
|
||||||
resources: ["secrets"]
|
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"]
|
verbs: ["get", "patch", "update"]
|
||||||
---
|
---
|
||||||
apiVersion: rbac.authorization.k8s.io/v1
|
apiVersion: rbac.authorization.k8s.io/v1
|
||||||
@@ -400,7 +400,7 @@ metadata:
|
|||||||
rules:
|
rules:
|
||||||
- apiGroups: [""]
|
- apiGroups: [""]
|
||||||
resources: ["secrets"]
|
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"]
|
verbs: ["get"]
|
||||||
---
|
---
|
||||||
apiVersion: rbac.authorization.k8s.io/v1
|
apiVersion: rbac.authorization.k8s.io/v1
|
||||||
|
|||||||
@@ -51,16 +51,16 @@ export const backendProfileSpecs: readonly BackendProfileSpec[] = [
|
|||||||
description: "MiniMax M3 OpenAI-compatible profile through Codex app-server stdio",
|
description: "MiniMax M3 OpenAI-compatible profile through Codex app-server stdio",
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
profile: "ofcx-go",
|
profile: "dsflash-go",
|
||||||
backendKind: "codex-app-server-stdio",
|
backendKind: "codex-app-server-stdio",
|
||||||
protocol: "codex-app-server-jsonrpc-stdio",
|
protocol: "codex-app-server-jsonrpc-stdio",
|
||||||
transport: "stdio",
|
transport: "stdio",
|
||||||
command: "codex app-server --listen stdio://",
|
command: "codex app-server --listen stdio://",
|
||||||
status: "registered",
|
status: "registered",
|
||||||
requiredSecretKeys: ["auth.json", "config.toml"],
|
requiredSecretKeys: ["auth.json", "config.toml"],
|
||||||
defaultSecretName: "agentrun-v01-provider-ofcx-go",
|
defaultSecretName: "agentrun-v01-provider-dsflash-go",
|
||||||
profileIsolation: "profile-scoped-codex-home",
|
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",
|
||||||
},
|
},
|
||||||
];
|
];
|
||||||
|
|
||||||
|
|||||||
+1
-1
@@ -28,7 +28,7 @@ export type FailureKind =
|
|||||||
export type RunStatus = "pending" | "claimed" | "running" | "completed" | "failed" | "blocked" | "cancelled";
|
export type RunStatus = "pending" | "claimed" | "running" | "completed" | "failed" | "blocked" | "cancelled";
|
||||||
export type CommandState = "pending" | "acknowledged" | "completed" | "failed" | "cancelled";
|
export type CommandState = "pending" | "acknowledged" | "completed" | "failed" | "cancelled";
|
||||||
export type TerminalStatus = "completed" | "failed" | "blocked" | "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 QueueTaskState = "pending" | "running" | "completed" | "failed" | "blocked" | "cancelled";
|
||||||
export type SessionExecutionState = "idle" | "running" | "terminal";
|
export type SessionExecutionState = "idle" | "running" | "terminal";
|
||||||
export type SessionAttentionState = "active" | "unread" | "read";
|
export type SessionAttentionState = "active" | "unread" | "read";
|
||||||
|
|||||||
@@ -137,6 +137,39 @@ ON CONFLICT (profile) DO UPDATE SET
|
|||||||
updated_at = EXCLUDED.updated_at;
|
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 = `
|
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 version bigint NOT NULL DEFAULT 1;
|
||||||
ALTER TABLE agentrun_sessions ADD COLUMN IF NOT EXISTS execution_state text NOT NULL DEFAULT 'idle';
|
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),
|
checksum: checksumSql(sessionStateStorageMigrationSql),
|
||||||
sql: sessionStateStorageMigrationSql,
|
sql: sessionStateStorageMigrationSql,
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
id: "008_v01_dsflash_go_backend_profile",
|
||||||
|
checksum: checksumSql(dsflashGoBackendProfileMigrationSql),
|
||||||
|
sql: dsflashGoBackendProfileMigrationSql,
|
||||||
|
},
|
||||||
];
|
];
|
||||||
|
|
||||||
export function postgresMigrationContract(): JsonRecord {
|
export function postgresMigrationContract(): JsonRecord {
|
||||||
|
|||||||
@@ -122,7 +122,7 @@ export async function setProviderProfileConfig(profileValue: string, body: unkno
|
|||||||
configHashSuffix: shortHash(configToml),
|
configHashSuffix: shortHash(configToml),
|
||||||
updatedAt: objectPath(applied, ["metadata", "annotations", `${credentialAnnotationPrefix}-updated-at`]) ?? new Date().toISOString(),
|
updatedAt: objectPath(applied, ["metadata", "annotations", `${credentialAnnotationPrefix}-updated-at`]) ?? new Date().toISOString(),
|
||||||
delegatedBy,
|
delegatedBy,
|
||||||
requiresExternalBridgeUpdate: profile === "deepseek",
|
requiresExternalBridgeUpdate: profile === "deepseek" || profile === "dsflash-go",
|
||||||
configTomlPrinted: false,
|
configTomlPrinted: false,
|
||||||
credentialValuesPrinted: false,
|
credentialValuesPrinted: false,
|
||||||
valuesPrinted: 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(),
|
updatedAt: objectPath(applied, ["metadata", "annotations", `${credentialAnnotationPrefix}-updated-at`]) ?? new Date().toISOString(),
|
||||||
configSummary: rendered.config.configSummary,
|
configSummary: rendered.config.configSummary,
|
||||||
delegatedBy,
|
delegatedBy,
|
||||||
requiresExternalBridgeUpdate: profile === "deepseek",
|
requiresExternalBridgeUpdate: profile === "deepseek" || profile === "dsflash-go",
|
||||||
valuesPrinted: false,
|
valuesPrinted: false,
|
||||||
pollCommands: {
|
pollCommands: {
|
||||||
show: `./scripts/agentrun provider-profiles show ${profile}`,
|
show: `./scripts/agentrun provider-profiles show ${profile}`,
|
||||||
@@ -297,14 +297,15 @@ function authPayload(apiKey: string): JsonRecord {
|
|||||||
}
|
}
|
||||||
|
|
||||||
function renderConfigToml(config: ProfileConfig): string {
|
function renderConfigToml(config: ProfileConfig): string {
|
||||||
|
const { contextWindow, autoCompactTokenLimit } = contextWindowSettings(config.model);
|
||||||
return [
|
return [
|
||||||
`model_provider = ${tomlString(config.providerName)}`,
|
`model_provider = ${tomlString(config.providerName)}`,
|
||||||
`model = ${tomlString(config.model)}`,
|
`model = ${tomlString(config.model)}`,
|
||||||
`review_model = ${tomlString(config.model)}`,
|
`review_model = ${tomlString(config.model)}`,
|
||||||
"disable_response_storage = true",
|
"disable_response_storage = true",
|
||||||
"network_access = \"enabled\"",
|
"network_access = \"enabled\"",
|
||||||
"model_context_window = 128000",
|
`model_context_window = ${contextWindow}`,
|
||||||
"model_auto_compact_token_limit = 110000",
|
`model_auto_compact_token_limit = ${autoCompactTokenLimit}`,
|
||||||
"approvals_reviewer = \"user\"",
|
"approvals_reviewer = \"user\"",
|
||||||
"",
|
"",
|
||||||
`[model_providers.${config.providerName}]`,
|
`[model_providers.${config.providerName}]`,
|
||||||
@@ -368,8 +369,8 @@ async function existingConfigToml(profile: BackendProfile, options: ProviderProf
|
|||||||
|
|
||||||
function existingConfigAllowed(profile: BackendProfile, configToml: string): boolean {
|
function existingConfigAllowed(profile: BackendProfile, configToml: string): boolean {
|
||||||
if (configToml.trim().length === 0) return false;
|
if (configToml.trim().length === 0) return false;
|
||||||
if (profile === "deepseek" && configToml.includes("hyueapi.com")) return false;
|
if ((profile === "deepseek" || profile === "dsflash-go") && 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("hwlab-deepseek-proxy.hwlab-v02.svc.cluster.local")) return false;
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -414,7 +415,7 @@ function defaultConfig(profile: BackendProfile): ProfileConfig {
|
|||||||
displayName: "OpenAI",
|
displayName: "OpenAI",
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
if (profile === "ofcx-go") {
|
if (profile === "dsflash-go") {
|
||||||
return {
|
return {
|
||||||
model: "deepseek-v4-flash",
|
model: "deepseek-v4-flash",
|
||||||
providerName: "opencode",
|
providerName: "opencode",
|
||||||
@@ -451,14 +452,21 @@ function validateBaseUrl(profile: BackendProfile, value: string): void {
|
|||||||
} catch {
|
} catch {
|
||||||
throw new AgentRunError("schema-invalid", "config.baseUrl must be a valid URL", { httpStatus: 400 });
|
throw new AgentRunError("schema-invalid", "config.baseUrl must be a valid URL", { httpStatus: 400 });
|
||||||
}
|
}
|
||||||
if (profile === "deepseek" && url.hostname === "hyueapi.com") {
|
if ((profile === "deepseek" || profile === "dsflash-go") && url.hostname === "hyueapi.com") {
|
||||||
throw new AgentRunError("tenant-policy-denied", "deepseek profile must use HWLAB Moon Bridge, not hyueapi.com", { httpStatus: 403 });
|
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") {
|
if ((profile === "deepseek" || profile === "dsflash-go") && 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 });
|
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 {
|
function validationExecutionPolicy(profile: BackendProfile, namespace: string): ExecutionPolicy {
|
||||||
const spec = requiredSpec(profile);
|
const spec = requiredSpec(profile);
|
||||||
return {
|
return {
|
||||||
|
|||||||
@@ -13,9 +13,9 @@ const selfTest: SelfTestCase = async () => {
|
|||||||
(error) => error instanceof AgentRunError && error.failureKind === "infra-failed" && error.message.includes("DATABASE_URL is required"),
|
(error) => error instanceof AgentRunError && error.failureKind === "infra-failed" && error.message.includes("DATABASE_URL is required"),
|
||||||
);
|
);
|
||||||
const postgresContract = postgresMigrationContract();
|
const postgresContract = postgresMigrationContract();
|
||||||
assert.equal(postgresContract.latestMigrationId, "007_v01_session_state_storage");
|
assert.equal(postgresContract.latestMigrationId, "008_v01_dsflash_go_backend_profile");
|
||||||
assert.equal((postgresContract.migrationIds as string[]).includes("007_v01_session_state_storage"), true);
|
assert.equal((postgresContract.migrationIds as string[]).includes("008_v01_dsflash_go_backend_profile"), true);
|
||||||
assert.ok(typeof (postgresContract.checksums as Record<string, string>)["007_v01_session_state_storage"] === "string" && (postgresContract.checksums as Record<string, string>)["007_v01_session_state_storage"].length > 0);
|
assert.ok(typeof (postgresContract.checksums as Record<string, string>)["008_v01_dsflash_go_backend_profile"] === "string" && (postgresContract.checksums as Record<string, string>)["008_v01_dsflash_go_backend_profile"].length > 0);
|
||||||
assert.equal((postgresContract.checksums as Record<string, string>)["002_v01_backend_profiles"], "928b5c490cc4539cb64ecef34784557601b2724fa2870570f16a53576804e49c");
|
assert.equal((postgresContract.checksums as Record<string, string>)["002_v01_backend_profiles"], "928b5c490cc4539cb64ecef34784557601b2724fa2870570f16a53576804e49c");
|
||||||
assert.ok(Array.isArray(postgresContract.requiredTables));
|
assert.ok(Array.isArray(postgresContract.requiredTables));
|
||||||
assert.ok(postgresContract.requiredTables.includes("agentrun_schema_migrations"));
|
assert.ok(postgresContract.requiredTables.includes("agentrun_schema_migrations"));
|
||||||
|
|||||||
@@ -86,6 +86,21 @@ const selfTest: SelfTestCase = async (context) => {
|
|||||||
assertRunnerJobDoesNotMountProfile(minimaxRendered.manifest as JsonRecord, "deepseek-0");
|
assertRunnerJobDoesNotMountProfile(minimaxRendered.manifest as JsonRecord, "deepseek-0");
|
||||||
assertNoSecretLeak(minimaxRendered);
|
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 fakeKubectl = path.join(context.tmp, "fake-kubectl.js");
|
||||||
const createdManifest = path.join(context.tmp, "created-runner-job.json");
|
const createdManifest = path.join(context.tmp, "created-runner-job.json");
|
||||||
await writeFile(fakeKubectl, `#!/usr/bin/env bun
|
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_NAMESPACE"), "agentrun-v01");
|
||||||
assert.equal(envMap.get("AGENTRUN_SESSION_PVC_MOUNT_PATH"), "/home/agentrun/.codex-codex/sessions");
|
assert.equal(envMap.get("AGENTRUN_SESSION_PVC_MOUNT_PATH"), "/home/agentrun/.codex-codex/sessions");
|
||||||
assert.equal(envMap.get("AGENTRUN_CODEX_ROLLOUT_SUBDIR"), "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 {
|
} finally {
|
||||||
await new Promise<void>((resolve) => server.server.close(() => resolve()));
|
await new Promise<void>((resolve) => server.server.close(() => resolve()));
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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");
|
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);
|
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(
|
await assert.rejects(
|
||||||
() => createRunWithCommand(client, { ...context, backendProfile: "deepseek", includeOnlyProfile: "codex" }, "missing deepseek", "selftest-deepseek-missing-secret", 15_000),
|
() => 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"),
|
(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 runSessionStorageSubdirCase({ client, managerUrl: server.baseUrl, context });
|
||||||
await runSessionStorageNoSecretLeakCase({ 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 {
|
} finally {
|
||||||
await new Promise<void>((resolve) => server.server.close(() => resolve()));
|
await new Promise<void>((resolve) => server.server.close(() => resolve()));
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -32,6 +32,12 @@ const selfTest: SelfTestCase = async (context) => {
|
|||||||
assert.equal(JSON.stringify(minimaxM3SecretPlan).includes("MiniMax-M3"), false);
|
assert.equal(JSON.stringify(minimaxM3SecretPlan).includes("MiniMax-M3"), false);
|
||||||
assert.equal(JSON.stringify(minimaxM3SecretPlan).includes("api.minimaxi.com"), 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(
|
await assert.rejects(
|
||||||
() => renderCodexProviderSecretPlan({ codexHome: path.join(context.tmp, "missing-codex-home"), dryRun: true }),
|
() => renderCodexProviderSecretPlan({ codexHome: path.join(context.tmp, "missing-codex-home"), dryRun: true }),
|
||||||
(error) => error instanceof AgentRunError && error.failureKind === "secret-unavailable",
|
(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",
|
(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;
|
export default selfTest;
|
||||||
|
|||||||
@@ -13,8 +13,8 @@ const selfTest: SelfTestCase = async (context) => {
|
|||||||
const gitopsRenderer = await readFile(path.join(context.root, "scripts/src/gitops-render.ts"), "utf8");
|
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("agentrun-v01-mgr-provider-secret-manager"), true);
|
||||||
assert.equal(gitopsRenderer.includes('verbs: ["get", "patch", "update"]'), 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);
|
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", "ofcx-go"]) {
|
for (const profile of ["codex", "deepseek", "minimax-m3", "dsflash-go"]) {
|
||||||
assert.equal(gitopsRenderer.includes(`agentrun-v01-provider-${profile}`), true);
|
assert.equal(gitopsRenderer.includes(`agentrun-v01-provider-${profile}`), true);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -56,8 +56,9 @@ console.log(JSON.stringify({ apiVersion: manifest.apiVersion, kind: manifest.kin
|
|||||||
async function assertBackendPreflight(client: ManagerClient): Promise<void> {
|
async function assertBackendPreflight(client: ManagerClient): Promise<void> {
|
||||||
const response = await client.get("/api/v1/backends") as { items?: JsonRecord[] };
|
const response = await client.get("/api/v1/backends") as { items?: JsonRecord[] };
|
||||||
const items = response.items ?? [];
|
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 === "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) {
|
for (const item of items) {
|
||||||
const preflight = item.preflight as JsonRecord;
|
const preflight = item.preflight as JsonRecord;
|
||||||
const defaultSecretRef = item.defaultSecretRef as JsonRecord;
|
const defaultSecretRef = item.defaultSecretRef as JsonRecord;
|
||||||
|
|||||||
@@ -109,6 +109,7 @@ export function assertNoSecretLeak(value: unknown): void {
|
|||||||
|
|
||||||
export function profileSecretHome(context: Pick<SelfTestContext, "codexHome"> & Partial<Pick<SelfTestContext, "deepseekHome" | "minimaxM3Home">>, profile: BackendProfile): string {
|
export function profileSecretHome(context: Pick<SelfTestContext, "codexHome"> & Partial<Pick<SelfTestContext, "deepseekHome" | "minimaxM3Home">>, profile: BackendProfile): string {
|
||||||
if (profile === "deepseek") return context.deepseekHome ?? context.codexHome;
|
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;
|
if (profile === "minimax-m3") return context.minimaxM3Home ?? context.codexHome;
|
||||||
return context.codexHome;
|
return context.codexHome;
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user