Merge pull request #2096 from Molecule-AI/refactor/remove-canvas-hermes-runtime-profile-2054

refactor(canvas): remove RUNTIME_PROFILES.hermes — value flows server-side (#2054 phase 3)
This commit is contained in:
Hongming Wang 2026-04-26 22:05:42 +00:00 committed by GitHub
commit ccb961a17b
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
2 changed files with 39 additions and 27 deletions

View File

@ -226,13 +226,18 @@ describe("ProvisioningTimeout", () => {
);
});
it("returns hermes override when runtime = hermes", () => {
it("hermes returns default — value moved server-side post-#2054 phase 3", () => {
// RUNTIME_PROFILES.hermes was removed when template-hermes
// started declaring provision_timeout_seconds in its
// config.yaml. The value now flows server-side via the
// workspace API → WorkspaceData.provision_timeout_ms →
// resolver overrides path. With no override supplied, the
// resolver falls through to the default — same as any other
// runtime without a canvas-side override.
expect(provisionTimeoutForRuntime("hermes")).toBe(
RUNTIME_PROFILES.hermes?.provisionTimeoutMs,
);
expect(provisionTimeoutForRuntime("hermes")).toBeGreaterThanOrEqual(
DEFAULT_RUNTIME_PROFILE.provisionTimeoutMs * 5,
DEFAULT_RUNTIME_PROFILE.provisionTimeoutMs,
);
expect(RUNTIME_PROFILES.hermes).toBeUndefined();
});
it("server-side workspace override wins over runtime profile", () => {
@ -309,7 +314,7 @@ describe("ProvisioningTimeout", () => {
expect(node?.data.provisionTimeoutMs).toBe(600_000);
});
it("absent provision_timeout_ms hydrates to null (falls through to runtime profile)", () => {
it("absent provision_timeout_ms hydrates to null (falls through to default post-cleanup)", () => {
useCanvasStore.getState().hydrate([
makeWS({ id: "ws-default", name: "Default", status: "provisioning", runtime: "hermes" }),
]);
@ -317,27 +322,32 @@ describe("ProvisioningTimeout", () => {
.getState()
.nodes.find((n) => n.id === "ws-default");
expect(node?.data.provisionTimeoutMs).toBeNull();
// And the resolver still returns hermes' profile value when
// no override is supplied — proves the fall-through stays intact.
// Post-#2054 phase 3: hermes no longer has a canvas-side
// RUNTIME_PROFILES entry. With no node override the resolver
// falls all the way through to DEFAULT_RUNTIME_PROFILE. In
// production the workspace-server-side template lookup
// populates node.provisionTimeoutMs to 720000 before this
// resolver runs (#2094); this test isolates the fall-through
// behavior when that population hasn't happened yet.
expect(
provisionTimeoutForRuntime("hermes", {
provisionTimeoutMs: node?.data.provisionTimeoutMs ?? undefined,
}),
).toBe(RUNTIME_PROFILES.hermes.provisionTimeoutMs);
).toBe(DEFAULT_RUNTIME_PROFILE.provisionTimeoutMs);
});
it("server override wins over runtime profile via the resolver path the component uses", () => {
// Mirrors ProvisioningTimeout.tsx:144 where node.provisionTimeoutMs
// is passed as overrides — verifies the resolver respects it
// even when the runtime has its own profile entry.
const override = 30_000;
it("server override wins over default via the resolver path the component uses", () => {
// Mirrors ProvisioningTimeout.tsx where node.provisionTimeoutMs
// is passed as overrides — verifies the resolver respects the
// override regardless of the runtime's profile state.
const override = 600_000;
expect(
provisionTimeoutForRuntime("hermes", {
provisionTimeoutMs: override,
}),
).toBe(override);
// Sanity — the runtime profile would have been much larger.
expect(RUNTIME_PROFILES.hermes.provisionTimeoutMs).toBeGreaterThan(
// Sanity — the override is the path that wins (default is much smaller).
expect(DEFAULT_RUNTIME_PROFILE.provisionTimeoutMs).toBeLessThan(
override,
);
});

View File

@ -60,21 +60,23 @@ export const DEFAULT_RUNTIME_PROFILE: Required<
/**
* Named per-runtime overrides. Keep this map small and explicit
* each entry is a deliberate statement that this runtime's cold-boot
* behavior differs materially from the default.
* behavior differs materially from the default AND that the runtime's
* template manifest hasn't yet declared a server-side
* `provision_timeout_seconds` (the preferred path post-#2054).
*
* Each override must also ship with a comment explaining WHY the default
* is wrong for this runtime. Unexplained numbers rot.
*
* Empty today `hermes` previously lived here at 720_000ms, but
* Molecule-AI/molecule-ai-workspace-template-hermes now declares the
* value in its config.yaml manifest, so the value flows through the
* server (workspace API WorkspaceData.provision_timeout_ms resolver
* overrides) instead of being canvas-hardcoded. New runtimes that need
* a non-default cold-boot threshold should follow the same pattern:
* declare `runtime_config.provision_timeout_seconds` in their template
* manifest, NOT add an entry here.
*/
export const RUNTIME_PROFILES: Record<string, RuntimeProfile> = {
hermes: {
// 12 min. Installs ripgrep + ffmpeg + node22 + builds hermes-agent
// from source + Playwright + Chromium (~300MB download). Measured
// cold boots on staging EC2 routinely land at 8-13 min. Aligns
// with SaaS E2E's PROVISION_TIMEOUT_SECS=900 (15 min) so the UI
// warning lands shortly before the backend itself gives up.
provisionTimeoutMs: 720_000,
},
};
export const RUNTIME_PROFILES: Record<string, RuntimeProfile> = {};
/**
* Data fields the canvas can consult for per-workspace overrides. These