chore: update managed runtime pins (#3416)

Co-authored-by: kandev-runtime-updater[bot] <kandev-runtime-updater[bot]@users.noreply.github.com>
Co-authored-by: Carlos Florencio <carlosmflorencio@gmail.com>
This commit is contained in:
github-actions[bot]
2026-09-06 11:35:59 +01:00
committed by GitHub
parent b086f41179
commit c112ec9844
6 changed files with 65 additions and 33 deletions
@@ -1,7 +1,7 @@
{
"@agentclientprotocol/claude-agent-acp": "0.70.0",
"@agentclientprotocol/codex-acp": "1.6.0",
"@github/copilot": "1.0.75",
"@google/gemini-cli": "0.52.0",
"opencode-ai": "1.18.18"
"@agentclientprotocol/claude-agent-acp": "0.75.1",
"@agentclientprotocol/codex-acp": "1.10.0",
"@github/copilot": "1.0.83",
"@google/gemini-cli": "0.58.0",
"opencode-ai": "1.18.29"
}
+5 -4
View File
@@ -4,15 +4,16 @@ set -eu
cache_root=${NPM_CONFIG_CACHE:-${npm_config_cache:-"$HOME/.npm"}}
package_spec=${3:-}
preference=${2:-}
managed_package_spec=opencode-ai@1.18.18
managed_package_name=opencode-ai
real_npx=/usr/bin/npx
# This image replaces npx only to make the selected managed runtime failure
# deterministic. Let every other package or invocation use the image's real
# npm implementation.
if [ "$package_spec" != "$managed_package_spec" ]; then
exec "$real_npx" "$@"
fi
case "$package_spec" in
"$managed_package_name"@*) ;;
*) exec "$real_npx" "$@" ;;
esac
key=$(printf '%s' "$package_spec" | sha512sum | cut -c1-16)
target_dir="$cache_root/_npx/$key"
+5 -1
View File
@@ -13,7 +13,7 @@ import type {
WorkflowProfileSessionEndPolicy,
TaskPriority,
} from "../../lib/types/http";
import type { Agent, AgentProfile } from "../../lib/types/http-agents";
import type { Agent, AgentProfile, AvailableAgent } from "../../lib/types/http-agents";
import { normalizeAgentProfile } from "../../lib/api/domains/agent-profile-normalize";
import type {
PRCommitDetail,
@@ -562,6 +562,10 @@ export class ApiClient {
};
}
async listAvailableAgents(): Promise<{ agents: AvailableAgent[]; total: number }> {
return this.request("GET", "/api/v1/agents/available");
}
async deleteAgentProfile(profileId: string, force?: boolean): Promise<void> {
const qs = force ? "?force=true" : "";
await this.request("DELETE", `/api/v1/agent-profiles/${profileId}${qs}`);
@@ -4,15 +4,18 @@ import type { BackendContext } from "../fixtures/backend";
import type { ApiClient } from "./api-client";
import type { AgentProfile } from "../../lib/types/http-agents";
export const MANAGED_RUNTIME_PACKAGE_SPEC = "opencode-ai@1.18.18";
export const MANAGED_RUNTIME_CACHE_ROOT = "/tmp/kandev-managed-npm-cache";
const MANAGED_RUNTIME_AGENT_NAME = "opencode-acp";
export function managedRuntimeExecutionCacheKey(
packageSpec = MANAGED_RUNTIME_PACKAGE_SPEC,
): string {
export function managedRuntimeExecutionCacheKey(packageSpec: string): string {
return createSha512(packageSpec).slice(0, 16);
}
export type ManagedRuntimePreparation = {
profile: AgentProfile;
packageSpec: string;
};
/**
* The real managed OpenCode agent is enabled only for this container-backed
* test. Its command runs through the image's npx wrapper, while the wrapper
@@ -21,23 +24,47 @@ export function managedRuntimeExecutionCacheKey(
export async function prepareManagedRuntimeProfile(
apiClient: ApiClient,
backend: BackendContext,
): Promise<AgentProfile> {
): Promise<ManagedRuntimePreparation> {
await backend.restart({ KANDEV_MOCK_AGENT: "true" });
let agentId = "";
let packageSpec = "";
let observedAgents = "";
try {
await expect
.poll(
async () => {
const { agents } = await apiClient.listAgents();
observedAgents = agents.map((agent) => `${agent.id}:${agent.name}`).join(", ");
agentId = agents.find((agent) => agent.name === "opencode-acp")?.id ?? "";
return agentId;
const [{ agents: availableAgents }, { agents: persistedAgents }] = await Promise.all([
apiClient.listAvailableAgents(),
apiClient.listAgents(),
]);
observedAgents = availableAgents
.map((agent) => {
const runtime = agent.runtime_update;
const version = runtime?.effective_version ? `@${runtime.effective_version}` : "";
return `${agent.name}:${agent.available ? "available" : "unavailable"}${version}`;
})
.join(", ");
const managedAgent = availableAgents.find(
(agent) =>
agent.name === MANAGED_RUNTIME_AGENT_NAME &&
agent.available &&
agent.runtime_update?.supported &&
agent.runtime_update.package &&
agent.runtime_update.effective_version,
);
const persistedAgent = persistedAgents.find(
(agent) => agent.name === MANAGED_RUNTIME_AGENT_NAME,
);
agentId = persistedAgent?.id ?? "";
packageSpec = managedAgent?.runtime_update
? `${managedAgent.runtime_update.package}@${managedAgent.runtime_update.effective_version}`
: "";
return agentId && packageSpec ? `${agentId}:${packageSpec}` : "";
},
{
timeout: 30_000,
message: "OpenCode managed runtime should be registered for container recovery",
message: "OpenCode managed runtime metadata should be available for container recovery",
},
)
.not.toBe("");
@@ -47,10 +74,13 @@ export async function prepareManagedRuntimeProfile(
);
}
return apiClient.createAgentProfile(agentId, "E2E managed npm recovery", {
model: "mock-fast",
env_vars: [{ key: "NPM_CONFIG_CACHE", value: MANAGED_RUNTIME_CACHE_ROOT }],
});
return {
profile: await apiClient.createAgentProfile(agentId, "E2E managed npm recovery", {
model: "mock-fast",
env_vars: [{ key: "NPM_CONFIG_CACHE", value: MANAGED_RUNTIME_CACHE_ROOT }],
}),
packageSpec,
};
}
/** Restore the normal e2e-only mock registry after a managed-runtime test. */
@@ -3,7 +3,6 @@ import { dockerFileContent, dockerPathExists } from "../../helpers/docker";
import { waitForLatestSessionDone } from "../../helpers/session";
import {
MANAGED_RUNTIME_CACHE_ROOT,
MANAGED_RUNTIME_PACKAGE_SPEC,
managedRuntimeExecutionCacheKey,
prepareManagedRuntimeProfile,
restoreE2EAgentRegistry,
@@ -20,7 +19,7 @@ test.describe("Docker executor - managed npm runtime recovery", () => {
test.setTimeout(240_000);
let profileId = "";
try {
const profile = await prepareManagedRuntimeProfile(apiClient, backend);
const { profile, packageSpec } = await prepareManagedRuntimeProfile(apiClient, backend);
profileId = profile.id;
const task = await apiClient.createTaskWithAgent(
seedData.workspaceId,
@@ -38,7 +37,7 @@ test.describe("Docker executor - managed npm runtime recovery", () => {
await waitForLatestSessionDone(apiClient, task.id, 1, "Wait for Docker managed recovery");
const environment = await apiClient.getTaskEnvironment(task.id);
expect(environment?.container_id).toBeTruthy();
const target = `${MANAGED_RUNTIME_CACHE_ROOT}/_npx/${managedRuntimeExecutionCacheKey()}`;
const target = `${MANAGED_RUNTIME_CACHE_ROOT}/_npx/${managedRuntimeExecutionCacheKey(packageSpec)}`;
const sibling = `${MANAGED_RUNTIME_CACHE_ROOT}/_npx/0123456789abcdef`;
const containerID = environment!.container_id!;
expect(dockerPathExists(containerID, `${target}/stale-marker`)).toBe(false);
@@ -48,7 +47,7 @@ test.describe("Docker executor - managed npm runtime recovery", () => {
containerID,
`${MANAGED_RUNTIME_CACHE_ROOT}/online-invocations`,
);
expect(onlineInvocations.trim().split(/\r?\n/)).toEqual([MANAGED_RUNTIME_PACKAGE_SPEC]);
expect(onlineInvocations.trim().split(/\r?\n/)).toEqual([packageSpec]);
await testPage.goto(`/t/${task.id}`);
const session = new SessionPage(testPage);
@@ -3,7 +3,6 @@ import { readRemoteFile, remotePathExists } from "../../helpers/ssh";
import { waitForLatestSessionDone } from "../../helpers/session";
import {
MANAGED_RUNTIME_CACHE_ROOT,
MANAGED_RUNTIME_PACKAGE_SPEC,
managedRuntimeExecutionCacheKey,
prepareManagedRuntimeProfile,
restoreE2EAgentRegistry,
@@ -20,7 +19,7 @@ test.describe("SSH executor - managed npm runtime recovery", () => {
test.setTimeout(240_000);
let profileId = "";
try {
const profile = await prepareManagedRuntimeProfile(apiClient, backend);
const { profile, packageSpec } = await prepareManagedRuntimeProfile(apiClient, backend);
profileId = profile.id;
const task = await apiClient.createTaskWithAgent(
seedData.workspaceId,
@@ -40,7 +39,7 @@ test.describe("SSH executor - managed npm runtime recovery", () => {
(candidate) => candidate.task_id === task.id,
);
expect(session?.remote_task_dir).toBeTruthy();
const target = `${MANAGED_RUNTIME_CACHE_ROOT}/_npx/${managedRuntimeExecutionCacheKey()}`;
const target = `${MANAGED_RUNTIME_CACHE_ROOT}/_npx/${managedRuntimeExecutionCacheKey(packageSpec)}`;
const sibling = `${MANAGED_RUNTIME_CACHE_ROOT}/_npx/0123456789abcdef`;
expect(remotePathExists(seedData.sshTarget, `${target}/stale-marker`)).toBe(false);
expect(readRemoteFile(seedData.sshTarget, `${target}/fresh-marker`)).toBe("fresh\n");
@@ -49,8 +48,7 @@ test.describe("SSH executor - managed npm runtime recovery", () => {
seedData.sshTarget,
`${MANAGED_RUNTIME_CACHE_ROOT}/online-invocations`,
);
expect(onlineInvocations.trim().split(/\r?\n/)).toEqual([MANAGED_RUNTIME_PACKAGE_SPEC]);
expect(MANAGED_RUNTIME_PACKAGE_SPEC).toBe("opencode-ai@1.18.18");
expect(onlineInvocations.trim().split(/\r?\n/)).toEqual([packageSpec]);
await testPage.goto(`/t/${task.id}`);
const page = new SessionPage(testPage);