File size: 4,410 Bytes
76289e7 | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 | // Context-engine host compatibility checks prevent engines from running on unsupported harnesses.
import type {
ContextEngine,
ContextEngineHostCapability,
ContextEngineHostRequirements,
ContextEngineInfo,
ContextEngineOperation,
} from "./types.js";
export type ContextEngineHostSupport = {
id: string;
label: string;
capabilities: readonly ContextEngineHostCapability[];
};
/** Return whether an engine implements the durable method matching its declared contract. */
export function supportsContextEngineDurableTurnAdvancement(engine: ContextEngine): boolean {
return (
engine.info.transcriptSemantics?.turnAdvancementIdempotency === "atomic-idempotent-v1" &&
typeof engine.commitTurn === "function"
);
}
const GENERIC_CLI_CONTEXT_ENGINE_HOST_CAPABILITIES = [
"bootstrap",
"after-turn",
"maintain",
] as const satisfies readonly ContextEngineHostCapability[];
export const OPENCLAW_EMBEDDED_CONTEXT_ENGINE_HOST = {
id: "openclaw-embedded",
label: "OpenClaw embedded runner",
capabilities: [
"bootstrap",
"assemble-before-prompt",
"after-turn",
"maintain",
"compact",
"runtime-llm-complete",
],
} as const satisfies ContextEngineHostSupport;
export const CODEX_APP_SERVER_CONTEXT_ENGINE_HOST = {
id: "codex-app-server",
label: "Codex app-server harness",
capabilities: [
"bootstrap",
"assemble-before-prompt",
"after-turn",
"maintain",
"compact",
"runtime-llm-complete",
"thread-bootstrap-projection",
],
} as const satisfies ContextEngineHostSupport;
type ContextEngineHostSupportEvaluation =
| {
ok: true;
requirements?: ContextEngineHostRequirements;
missingCapabilities: [];
}
| {
ok: false;
requirements: ContextEngineHostRequirements;
missingCapabilities: ContextEngineHostCapability[];
};
/** Build the default host support advertised by the generic CLI runner. */
export function buildGenericCliContextEngineHostSupport(params: {
backendId: string;
capabilities?: readonly ContextEngineHostCapability[];
}): ContextEngineHostSupport {
return {
id: `cli:${params.backendId}`,
label: `CLI backend "${params.backendId}"`,
capabilities: params.capabilities ?? GENERIC_CLI_CONTEXT_ENGINE_HOST_CAPABILITIES,
};
}
/** Evaluate whether a context-engine host can safely run the requested operation. */
export function evaluateContextEngineHostSupport(params: {
contextEngineInfo: ContextEngineInfo;
operation: ContextEngineOperation;
host: ContextEngineHostSupport;
}): ContextEngineHostSupportEvaluation {
const requirements = params.contextEngineInfo.hostRequirements?.[params.operation];
if (!requirements || requirements.requiredCapabilities.length === 0) {
return { ok: true, requirements, missingCapabilities: [] };
}
const supported = new Set(params.host.capabilities);
// Capabilities are host-advertised facts; requirements stay engine-authored per operation.
const missingCapabilities = requirements.requiredCapabilities.filter(
(capability) => !supported.has(capability),
);
if (missingCapabilities.length === 0) {
return { ok: true, requirements, missingCapabilities: [] };
}
return {
ok: false,
requirements,
missingCapabilities,
};
}
/** Assert that a context engine can safely run under the supplied host. */
export function assertContextEngineHostSupport(params: {
contextEngine: ContextEngine;
operation: ContextEngineOperation;
host: ContextEngineHostSupport;
}): void {
const evaluation = evaluateContextEngineHostSupport({
contextEngineInfo: params.contextEngine.info,
operation: params.operation,
host: params.host,
});
if (evaluation.ok) {
return;
}
const engineId = params.contextEngine.info.id;
const required = evaluation.requirements.requiredCapabilities.join(", ");
const actual =
params.host.capabilities.length > 0 ? params.host.capabilities.join(", ") : "(none)";
const guidance = evaluation.requirements.unsupportedMessage
? ` ${evaluation.requirements.unsupportedMessage}`
: "";
throw new Error(
`Context engine "${engineId}" cannot run operation "${params.operation}" on ${params.host.label}. ` +
`Missing host capabilities: ${evaluation.missingCapabilities.join(", ")}. ` +
`Required capabilities: ${required}. ` +
`Host capabilities: ${actual}.${guidance}`,
);
}
|