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:
committed by
GitHub
parent
b086f41179
commit
c112ec9844
@@ -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"
|
||||
}
|
||||
|
||||
@@ -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"
|
||||
|
||||
@@ -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);
|
||||
|
||||
Reference in New Issue
Block a user