From 60a15186e5cd97349445a71404e9236671301b9d Mon Sep 17 00:00:00 2001 From: Codex Date: Tue, 2 Jun 2026 19:02:58 +0800 Subject: [PATCH] fix: assemble unidesk ssh for web agentrun turns --- internal/cloud/code-agent-agentrun-adapter.ts | 30 +++++++++++++++++-- internal/cloud/server-agent-chat.test.ts | 17 ++++++++--- scripts/g14-gitops-render.mjs | 1 + scripts/g14-gitops-render.test.ts | 1 + 4 files changed, 42 insertions(+), 7 deletions(-) diff --git a/internal/cloud/code-agent-agentrun-adapter.ts b/internal/cloud/code-agent-agentrun-adapter.ts index 7e069350..d6c30d67 100644 --- a/internal/cloud/code-agent-agentrun-adapter.ts +++ b/internal/cloud/code-agent-agentrun-adapter.ts @@ -34,7 +34,8 @@ const THREAD_CONTINUITY_POLICY = "hwlab-agentrun-v01-reuse-runner-thread"; const SESSION_POLICY_RUN_LOCAL = "hwlab-agentrun-v01-session-runner-reuse"; const TERMINAL_RUN_STATUSES = new Set(["completed", "failed", "blocked", "cancelled", "canceled"]); const HWLAB_RESOURCE_TOOL_ALIASES = Object.freeze([ - Object.freeze({ name: "hwpod", path: "tools/device-pod-cli.mjs", kind: "node-script" }) + Object.freeze({ name: "hwpod", path: "tools/device-pod-cli.mjs", kind: "node-script" }), + Object.freeze({ name: "unidesk-ssh", path: "tools/unidesk-ssh.mjs", kind: "bun-script" }) ]); export function codeAgentAgentRunAdapterEnabled(env = process.env) { @@ -504,7 +505,8 @@ function buildAgentRunCreateRunInput({ params, env, traceId, backendProfile, ses network: firstNonEmpty(env.HWLAB_CODE_AGENT_AGENTRUN_NETWORK, "enabled"), secretScope: { allowCredentialEcho: false, - providerCredentials: [providerCredentialSecretRef(backendProfile, env)] + providerCredentials: [providerCredentialSecretRef(backendProfile, env)], + toolCredentials: agentRunToolCredentials(env) } }, traceSink: { @@ -587,7 +589,8 @@ function buildAgentRunTransientEnv(env = process.env) { "HWLAB_RUNTIME_LANE", "HWLAB_RUNTIME_ENDPOINT_LOCKED", "HWLAB_CODE_AGENT_ASSEMBLED_RUNTIME", - "HWLAB_DEVICE_POD_API_KEY" + "HWLAB_DEVICE_POD_API_KEY", + "UNIDESK_MAIN_SERVER_IP" ]) { const value = firstNonEmpty(env[name]); if (value) entries.push({ name, value, sensitive: name === "HWLAB_DEVICE_POD_API_KEY" }); @@ -595,6 +598,27 @@ function buildAgentRunTransientEnv(env = process.env) { return entries; } +function agentRunToolCredentials(env = process.env) { + const namespace = firstNonEmpty(env.HWLAB_CODE_AGENT_AGENTRUN_TOOL_SECRET_NAMESPACE, env.HWLAB_CODE_AGENT_AGENTRUN_SECRET_NAMESPACE, DEFAULT_RUNNER_NAMESPACE); + const githubSecretName = firstNonEmpty(env.HWLAB_CODE_AGENT_AGENTRUN_GITHUB_TOOL_SECRET_NAME, "agentrun-v01-tool-github-pr"); + const githubSecretKey = firstNonEmpty(env.HWLAB_CODE_AGENT_AGENTRUN_GITHUB_TOOL_SECRET_KEY, "GH_TOKEN"); + const unideskSecretName = firstNonEmpty(env.HWLAB_CODE_AGENT_AGENTRUN_UNIDESK_SSH_TOOL_SECRET_NAME, "agentrun-v01-tool-unidesk-ssh"); + return [ + { + tool: "github", + purpose: "pull-request", + secretRef: { namespace, name: githubSecretName, keys: [githubSecretKey] }, + projection: { kind: "env", envName: githubSecretKey, secretKey: githubSecretKey } + }, + { + tool: "unidesk-ssh", + purpose: "ssh-passthrough", + secretRef: { namespace, name: unideskSecretName, keys: ["UNIDESK_SSH_CLIENT_TOKEN"] }, + projection: { kind: "env", envName: "UNIDESK_SSH_CLIENT_TOKEN", secretKey: "UNIDESK_SSH_CLIENT_TOKEN" } + } + ]; +} + async function resolveReusableAgentRun({ params = {}, options = {}, env = process.env, managerUrl, fetchImpl, timeoutMs, backendProfile, traceId, traceStore }) { const hwlabSessionId = hwlabSessionIdForParams(params, traceId); if (!safeSessionId(hwlabSessionId) || hwlabSessionId === agentRunSessionId(traceId) || typeof options.accessController?.getAgentSession !== "function") { diff --git a/internal/cloud/server-agent-chat.test.ts b/internal/cloud/server-agent-chat.test.ts index ca2987f3..fc1edffa 100644 --- a/internal/cloud/server-agent-chat.test.ts +++ b/internal/cloud/server-agent-chat.test.ts @@ -173,8 +173,12 @@ test("cloud api /v1/agent/chat delegates v0.2 turns to AgentRun v0.1 over adapte assert.equal(body.resourceBundleRef.repoUrl, "http://git-mirror-http.devops-infra.svc.cluster.local/pikasTech/HWLAB.git"); assert.equal(body.resourceBundleRef.commitId, "0123456789abcdef0123456789abcdef01234567"); assert.deepEqual(body.resourceBundleRef.toolAliases, [ - { name: "hwpod", path: "tools/device-pod-cli.mjs", kind: "node-script" } + { name: "hwpod", path: "tools/device-pod-cli.mjs", kind: "node-script" }, + { name: "unidesk-ssh", path: "tools/unidesk-ssh.mjs", kind: "bun-script" } ]); + const toolCredentials = body.executionPolicy.secretScope.toolCredentials; + assert.equal(toolCredentials.some((item) => item.tool === "github" && item.projection.envName === "GH_TOKEN" && item.secretRef.name === "agentrun-v01-tool-github-pr"), true); + assert.equal(toolCredentials.some((item) => item.tool === "unidesk-ssh" && item.projection.envName === "UNIDESK_SSH_CLIENT_TOKEN" && item.secretRef.name === "agentrun-v01-tool-unidesk-ssh"), true); assert.equal(body.sessionRef.threadId, "019e8078-db67-7750-a5d9-1a99f3abd445"); assert.equal(body.sessionRef.sessionId, "ses_agentrun_deepseek_server_test_agentrun"); assert.equal(body.sessionRef.metadata.hwlabSessionId, "ses_server-test-agentrun"); @@ -231,7 +235,8 @@ test("cloud api /v1/agent/chat delegates v0.2 turns to AgentRun v0.1 over adapte "HWLAB_RUNTIME_LANE", "HWLAB_RUNTIME_ENDPOINT_LOCKED", "HWLAB_CODE_AGENT_ASSEMBLED_RUNTIME", - "HWLAB_DEVICE_POD_API_KEY" + "HWLAB_DEVICE_POD_API_KEY", + "UNIDESK_MAIN_SERVER_IP" ]); const transientEnv = Object.fromEntries(body.transientEnv.map((entry) => [entry.name, entry.value])); assert.equal(transientEnv.HWLAB_RUNTIME_API_URL, "http://hwlab-cloud-api.hwlab-v02.svc.cluster.local:6667"); @@ -241,7 +246,10 @@ test("cloud api /v1/agent/chat delegates v0.2 turns to AgentRun v0.1 over adapte assert.equal(transientEnv.HWLAB_RUNTIME_ENDPOINT_LOCKED, "1"); assert.equal(transientEnv.HWLAB_CODE_AGENT_ASSEMBLED_RUNTIME, "1"); assert.equal(transientEnv.HWLAB_DEVICE_POD_API_KEY, "test-device-pod-api-key"); - assert.ok(body.transientEnv.length >= 7); + assert.equal(transientEnv.UNIDESK_MAIN_SERVER_IP, "http://74.48.78.17:18081"); + assert.ok(body.transientEnv.length >= 8); + assert.equal(Object.hasOwn(transientEnv, "UNIDESK_SSH_CLIENT_TOKEN"), false); + assert.equal(Object.hasOwn(transientEnv, "GH_TOKEN"), false); assert.equal(Object.hasOwn(transientEnv, "HWLAB_DEVICE_POD_API_URL"), false); assert.equal(Object.hasOwn(transientEnv, "HWLAB_CODE_AGENT_DEVICE_POD_API_URL"), false); return send({ @@ -328,7 +336,8 @@ test("cloud api /v1/agent/chat delegates v0.2 turns to AgentRun v0.1 over adapte HWLAB_CODE_AGENT_DEFAULT_PROVIDER_PROFILE: "deepseek", HWLAB_CODE_AGENT_DEEPSEEK_MODEL: "deepseek-chat", HWLAB_ENVIRONMENT: "v02", - HWLAB_GITOPS_PROFILE: "v02" + HWLAB_GITOPS_PROFILE: "v02", + UNIDESK_MAIN_SERVER_IP: "http://74.48.78.17:18081" }, accessController: { required: false, diff --git a/scripts/g14-gitops-render.mjs b/scripts/g14-gitops-render.mjs index 69b5bd7a..3ab0de88 100644 --- a/scripts/g14-gitops-render.mjs +++ b/scripts/g14-gitops-render.mjs @@ -881,6 +881,7 @@ function transformWorkloads({ workloads, deploy, catalog, source, sourceBranch = upsertEnv(container.env, "HWLAB_CODE_AGENT_AGENTRUN_RUNNER_NAMESPACE", "agentrun-v01"); upsertEnv(container.env, "HWLAB_CODE_AGENT_AGENTRUN_SECRET_NAMESPACE", "agentrun-v01"); upsertEnv(container.env, "HWLAB_CODE_AGENT_AGENTRUN_REPO_URL", "http://git-mirror-http.devops-infra.svc.cluster.local/pikasTech/HWLAB.git"); + upsertEnv(container.env, "UNIDESK_MAIN_SERVER_IP", "http://74.48.78.17:18081"); } upsertEnv(container.env, "HWLAB_CODE_AGENT_DEFAULT_PROVIDER_PROFILE", "deepseek"); upsertEnv(container.env, "HWLAB_CODE_AGENT_DEEPSEEK_MODEL", deepSeekProfileModel); diff --git a/scripts/g14-gitops-render.test.ts b/scripts/g14-gitops-render.test.ts index 3315a108..0813f53f 100644 --- a/scripts/g14-gitops-render.test.ts +++ b/scripts/g14-gitops-render.test.ts @@ -231,6 +231,7 @@ test("v02 render follows TypeScript runtime checks and does not self-patch boots assert.ok(cloudApi, "expected v02 hwlab-cloud-api workload"); const cloudApiEnv = cloudApi.spec.template.spec.containers[0].env; assert.ok(cloudApiEnv.some((entry) => entry.name === "HWLAB_CODE_AGENT_AGENTRUN_SOURCE_COMMIT" && entry.value === sourceRevision)); + assert.ok(cloudApiEnv.some((entry) => entry.name === "UNIDESK_MAIN_SERVER_IP" && entry.value === "http://74.48.78.17:18081")); const agentWorker = workloadsJson.items.find((item) => item.metadata?.labels?.["hwlab.pikastech.local/service-id"] === "hwlab-agent-worker"); assert.ok(agentWorker, "expected v02 hwlab-agent-worker suspended Job template"); const agentWorkerEnv = agentWorker?.spec?.template?.spec?.containers?.[0]?.env ?? [];