diff --git a/config/agentrun.yaml b/config/agentrun.yaml index 1c7ea73e..ec7d215d 100644 --- a/config/agentrun.yaml +++ b/config/agentrun.yaml @@ -48,6 +48,8 @@ nativeDevelopment: image: 127.0.0.1:5000/agentrun/agentrun-mgr-env@sha256:929c350b07b48aac8450ff52e5ca575686016cf85192af435700e8efb85b0e7b serviceAccount: agentrun-nc01-v02-runner jobNamePrefix: agentrun-nc01-v02-l1-runner + nodeSelector: + unidesk.ai/node-id: NC01 apiKeySecretRef: name: agentrun-v02-api-key key: HWLAB_API_KEY diff --git a/scripts/src/agentrun/native-development.ts b/scripts/src/agentrun/native-development.ts index ed483692..c81dc684 100644 --- a/scripts/src/agentrun/native-development.ts +++ b/scripts/src/agentrun/native-development.ts @@ -35,6 +35,7 @@ interface AgentRunNativeManagerSpec { image: string; serviceAccount: string; jobNamePrefix: string; + nodeSelector: Record; apiKeySecretRef: { name: string; key: string }; idleTimeoutMs: number; backendRetry: { maxAttempts: number; initialBackoffMs: number; maxBackoffMs: number }; @@ -176,6 +177,7 @@ function nativeEnvironment(spec: AgentRunNativeManagerSpec): NodeJS.ProcessEnv { AGENTRUN_RUNNER_IMAGE: spec.runner.image, AGENTRUN_RUNNER_SERVICE_ACCOUNT: spec.runner.serviceAccount, AGENTRUN_RUNNER_JOB_NAME_PREFIX: spec.runner.jobNamePrefix, + AGENTRUN_RUNNER_NODE_SELECTOR_JSON: JSON.stringify(spec.runner.nodeSelector), AGENTRUN_RUNNER_API_KEY_SECRET_NAME: spec.runner.apiKeySecretRef.name, AGENTRUN_RUNNER_API_KEY_SECRET_KEY: spec.runner.apiKeySecretRef.key, AGENTRUN_RUNNER_IDLE_TIMEOUT_MS: String(spec.runner.idleTimeoutMs), @@ -276,6 +278,7 @@ function readNativeManagerSpec(): AgentRunNativeManagerSpec { image: stringField(runner, "image", `${CONFIG_PATH}.nativeDevelopment.manager.runner`), serviceAccount: stringField(runner, "serviceAccount", `${CONFIG_PATH}.nativeDevelopment.manager.runner`), jobNamePrefix: stringField(runner, "jobNamePrefix", `${CONFIG_PATH}.nativeDevelopment.manager.runner`), + nodeSelector: stringRecordField(runner, "nodeSelector", `${CONFIG_PATH}.nativeDevelopment.manager.runner`), apiKeySecretRef: { name: stringField(runnerSecret, "name", `${CONFIG_PATH}.nativeDevelopment.manager.runner.apiKeySecretRef`), key: stringField(runnerSecret, "key", `${CONFIG_PATH}.nativeDevelopment.manager.runner.apiKeySecretRef`), @@ -315,6 +318,18 @@ function positiveIntegerFields(record: Record return Object.fromEntries(fields.map((field) => [field, positiveInteger(record, field, path)])) as Record; } +function stringRecordField(record: Record, key: string, path: string): Record { + const value = recordField(record, key, path); + const entries = Object.entries(value); + if (entries.length === 0) throw new Error(`${path}.${key} must not be empty`); + return Object.fromEntries(entries.map(([entryKey, entryValue]) => { + if (entryKey.trim().length === 0 || typeof entryValue !== "string" || entryValue.trim().length === 0) { + throw new Error(`${path}.${key} entries must use non-empty string keys and values`); + } + return [entryKey, entryValue.trim()]; + })); +} + function positiveInteger(record: Record, key: string, path: string): number { const value = integerField(record, key, path); if (value < 1) throw new Error(`${path}.${key} must be positive`);