@sellable/install
Version:
One-command installer for Sellable MCP in Claude Code, Codex, and Hermes
3,175 lines • 126 kB
JavaScript
import { createHash, createHmac, timingSafeEqual } from "node:crypto";
import {
closeSync,
constants,
existsSync,
fchmodSync,
fchownSync,
fsyncSync,
lstatSync,
openSync,
readFileSync,
realpathSync,
renameSync,
unlinkSync,
writeFileSync,
} from "node:fs";
import { dirname, isAbsolute, join, relative, resolve, sep } from "node:path";
export const HERMES_AGENT_BRIDGE_ID = "sellable-agent-hermes-bridge/v1";
export const HERMES_AGENT_BRIDGE_MARKER = "SELLABLE_AGENT_HERMES_BRIDGE_V1";
export const HERMES_DEVELOPER_SLACK_METADATA_CONTRACT =
"hermes-developer-native-slack-metadata/v1";
const HERMES_DEVELOPER_NATIVE_SOURCE = "hermes-developer-node-socket-mode/v1";
const HERMES_DEVELOPER_EVENT_TYPES = new Set([
"app_mention",
"message",
"interactive",
]);
const HERMES_DEVELOPER_EVENT_SUBTYPES = new Set([
"",
"message_changed",
"message_deleted",
"unsupported",
]);
const HERMES_DEVELOPER_SLACK_ID = /^[A-Z][A-Z0-9]{8,31}$/;
const HERMES_DEVELOPER_SLACK_TS = /^\d{1,16}\.\d{6}$/;
const HERMES_DEVELOPER_EVENT_ID = /^[A-Za-z0-9_.:-]{1,128}$/;
const sha256 = (value) => createHash("sha256").update(value).digest("hex");
const isSha256 = (value) =>
typeof value === "string" && /^[a-f0-9]{64}$/.test(value);
function canonicalHermesDeveloperMetadata(value) {
if (Array.isArray(value)) return value.map(canonicalHermesDeveloperMetadata);
if (value && typeof value === "object") {
return Object.fromEntries(
Object.keys(value)
.sort()
.map((key) => [key, canonicalHermesDeveloperMetadata(value[key])])
);
}
return value;
}
function exactHermesDeveloperMetadataKeys(value, expected) {
return (
value &&
typeof value === "object" &&
!Array.isArray(value) &&
Object.keys(value).sort().join("\0") === [...expected].sort().join("\0")
);
}
/**
* Seal identity copied by the repo-owned Socket Mode receiver before any
* planner or worker execution. This deliberately has no text or tool
* arguments: downstream code cannot select a Slack principal, route, event or
* acknowledgement contract.
*/
export function createHermesDeveloperTrustedSlackMetadata(
input,
authenticationKey
) {
if (!Buffer.isBuffer(authenticationKey) || authenticationKey.length < 32) {
throw new HermesAgentBridgeError(
"HERMES_DEVELOPER_SLACK_METADATA_KEY_REQUIRED",
"Hermes developer Slack metadata requires a gateway-private authentication key"
);
}
const keys = [
"source",
"teamId",
"channelId",
"actorId",
"eventId",
"eventType",
"eventSubtype",
"messageTs",
"threadTs",
"botId",
"ackCapability",
"adapterGeneration",
];
if (
!exactHermesDeveloperMetadataKeys(input, keys) ||
input.source !== HERMES_DEVELOPER_NATIVE_SOURCE ||
!HERMES_DEVELOPER_SLACK_ID.test(input.teamId ?? "") ||
!HERMES_DEVELOPER_SLACK_ID.test(input.channelId ?? "") ||
!HERMES_DEVELOPER_SLACK_ID.test(input.actorId ?? "") ||
!HERMES_DEVELOPER_EVENT_ID.test(input.eventId ?? "") ||
!HERMES_DEVELOPER_EVENT_TYPES.has(input.eventType) ||
!HERMES_DEVELOPER_EVENT_SUBTYPES.has(input.eventSubtype ?? "") ||
!HERMES_DEVELOPER_SLACK_TS.test(input.messageTs ?? "") ||
(input.threadTs !== null &&
!HERMES_DEVELOPER_SLACK_TS.test(input.threadTs ?? "")) ||
(input.botId !== null &&
!HERMES_DEVELOPER_SLACK_ID.test(input.botId ?? "")) ||
input.ackCapability !== "defer_until_durable_intake" ||
!Number.isSafeInteger(input.adapterGeneration) ||
input.adapterGeneration < 1
) {
throw new HermesAgentBridgeError(
"HERMES_DEVELOPER_SLACK_METADATA_REJECTED",
"Hermes developer Slack metadata must come from the deferred-ack repo-owned receiver"
);
}
const body = canonicalHermesDeveloperMetadata({
contract: HERMES_DEVELOPER_SLACK_METADATA_CONTRACT,
...input,
});
const metadataDigest = sha256(JSON.stringify(body));
return Object.freeze({
...body,
metadataDigest,
authenticationTag: createHmac("sha256", authenticationKey)
.update(metadataDigest)
.digest("hex"),
});
}
export function verifyHermesDeveloperTrustedSlackMetadata(
value,
authenticationKey
) {
try {
if (!Buffer.isBuffer(authenticationKey) || authenticationKey.length < 32) {
return false;
}
if (
!exactHermesDeveloperMetadataKeys(value, [
"contract",
"source",
"teamId",
"channelId",
"actorId",
"eventId",
"eventType",
"eventSubtype",
"messageTs",
"threadTs",
"botId",
"ackCapability",
"adapterGeneration",
"metadataDigest",
"authenticationTag",
]) ||
value.contract !== HERMES_DEVELOPER_SLACK_METADATA_CONTRACT
) {
return false;
}
const {
contract: _contract,
metadataDigest,
authenticationTag,
...input
} = value;
const rebuilt = createHermesDeveloperTrustedSlackMetadata(
input,
authenticationKey
);
const supplied = Buffer.from(authenticationTag ?? "", "hex");
const expected = Buffer.from(rebuilt.authenticationTag, "hex");
return (
rebuilt.metadataDigest === metadataDigest &&
supplied.length === expected.length &&
timingSafeEqual(supplied, expected)
);
} catch {
return false;
}
}
export class HermesAgentBridgeError extends Error {
constructor(code, message, details = {}) {
super(message);
this.name = "HermesAgentBridgeError";
this.code = code;
this.details = details;
}
}
function replaceExactlyOnce(source, needle, replacement, label) {
const first = source.indexOf(needle);
const last = source.lastIndexOf(needle);
if (first < 0 || first !== last) {
throw new HermesAgentBridgeError(
"HERMES_BRIDGE_PATCH_ANCHOR_MISMATCH",
`Expected exactly one ${label} patch anchor`,
{ label }
);
}
return `${source.slice(0, first)}${replacement}${source.slice(first + needle.length)}`;
}
const SECRET_FD_HELPER = `
# ${HERMES_AGENT_BRIDGE_MARKER}: inherited Slack secret reader.
_SELLABLE_AGENT_SECRET_CACHE = {}
def _sellable_agent_read_slack_secret(fd: int, env_name: str, prefix: str):
if os.getenv("SELLABLE_AGENT_RUNTIME", "") != "1":
return os.getenv(env_name)
if env_name in os.environ:
raise RuntimeError(f"{env_name} must not be present in the Sellable runtime environment")
cache_key = (fd, env_name, prefix)
if cache_key in _SELLABLE_AGENT_SECRET_CACHE:
return _SELLABLE_AGENT_SECRET_CACHE[cache_key]
try:
duplicate = os.dup(fd)
except OSError as exc:
raise RuntimeError(f"required inherited descriptor {fd} is unavailable") from exc
try:
chunks = []
size = 0
while True:
chunk = os.read(duplicate, min(1024, 4097 - size))
if not chunk:
break
chunks.append(chunk)
size += len(chunk)
if size > 4096:
raise RuntimeError(f"secret on descriptor {fd} exceeds the size limit")
finally:
os.close(duplicate)
try:
value = b"".join(chunks).decode("utf-8").strip()
except UnicodeDecodeError as exc:
raise RuntimeError(f"secret on descriptor {fd} is not valid UTF-8") from exc
if not value or "\\x00" in value or "\\n" in value or "\\r" in value:
raise RuntimeError(f"secret on descriptor {fd} is malformed")
if not value.startswith(prefix):
raise RuntimeError(f"secret on descriptor {fd} has the wrong credential class")
_SELLABLE_AGENT_SECRET_CACHE[cache_key] = value
return value
`;
const SLACK_TEST_API_HELPER = `
# ${HERMES_AGENT_BRIDGE_MARKER}: bounded whole-image Slack API seam.
def _sellable_agent_slack_api_kwargs():
if (
os.getenv("SELLABLE_AGENT_RUNTIME", "") != "1"
or os.getenv("SELLABLE_AGENT_ALLOW_TEST_OIDC", "") != "1"
):
return {}
origin = os.getenv("SELLABLE_AGENT_SLACK_API_ORIGIN", "")
from urllib.parse import urlparse
parsed = urlparse(origin)
if (
parsed.scheme != "http"
or parsed.hostname not in {"127.0.0.1", "host.docker.internal"}
or parsed.username
or parsed.password
or parsed.path not in {"", "/"}
or parsed.params
or parsed.query
or parsed.fragment
):
raise RuntimeError("Sellable whole-image Slack API origin is invalid")
return {"base_url": origin.rstrip("/") + "/api/"}
`;
const SLACK_DEDICATED_TEST_API_HELPER = `
# ${HERMES_AGENT_BRIDGE_MARKER}: bounded disposable Fly Slack API seam.
def _sellable_agent_slack_api_kwargs():
if (
os.getenv("SELLABLE_AGENT_RUNTIME", "") != "1"
or (
os.getenv("SELLABLE_AGENT_ALLOW_TEST_PROVIDERS", "") != "1"
and os.getenv("SELLABLE_AGENT_ALLOW_TEST_OIDC", "") != "1"
)
):
return {}
origin = os.getenv("SELLABLE_AGENT_SLACK_API_ORIGIN", "")
from urllib.parse import urlparse
parsed = urlparse(origin)
local_http = (
parsed.scheme == "http"
and parsed.hostname in {"127.0.0.1", "host.docker.internal"}
)
disposable_https = parsed.scheme == "https" and bool(parsed.hostname)
if (
not (local_http or disposable_https)
or parsed.username
or parsed.password
or parsed.path not in {"", "/"}
or parsed.params
or parsed.query
or parsed.fragment
):
raise RuntimeError("Sellable disposable Slack API origin is invalid")
return {"base_url": origin.rstrip("/") + "/api/"}
`;
const SLACK_MESSAGE_UNFURL_FILE_HELPER = `
# ${HERMES_AGENT_BRIDGE_MARKER}: recover files from bounded allowed-channel Slack message unfurls.
async def _sellable_agent_recover_slack_message_unfurl_files(
adapter,
attachments,
current_channel_id,
team_id,
existing_files=None,
):
if os.getenv("SELLABLE_AGENT_RUNTIME", "") != "1":
return []
if not current_channel_id or not team_id:
return []
message_unfurls = [
attachment
for attachment in list(attachments or [])
if isinstance(attachment, dict) and attachment.get("is_msg_unfurl") is True
][:3]
if not message_unfurls:
return []
client = adapter._team_clients.get(team_id)
if client is None:
logger.warning(
"[Slack] Refusing message-unfurl file recovery: exact workspace client is unavailable"
)
return []
allowed_channel_ids = {
channel_id.strip().upper()
for channel_id in os.getenv("SLACK_ALLOWED_CHANNELS", "").split(",")
if channel_id.strip()
}
if not allowed_channel_ids:
logger.warning(
"[Slack] Refusing message-unfurl file recovery: allowed channels are unavailable"
)
return []
seen_file_ids = {
str(file_obj.get("id"))
for file_obj in (existing_files or [])
if isinstance(file_obj, dict) and file_obj.get("id")
}
recovered = []
for attachment in message_unfurls:
target_channel_id = str(attachment.get("channel_id") or "")
target_ts = str(attachment.get("ts") or "")
if (
target_channel_id.upper() not in allowed_channel_ids
or re.fullmatch(r"\\d+\\.\\d{6}", target_ts) is None
):
continue
thread_ts = str(attachment.get("thread_ts") or "")
if thread_ts and re.fullmatch(r"\\d+\\.\\d{6}", thread_ts) is None:
thread_ts = ""
permalink = str(
attachment.get("from_url") or attachment.get("title_link") or ""
)
if permalink:
try:
from html import unescape
from urllib.parse import parse_qs, urlsplit
parsed = urlsplit(unescape(permalink))
path_match = re.fullmatch(
r"/archives/([CGD][A-Z0-9]{8,})/p(\\d{16})",
parsed.path,
re.IGNORECASE,
)
if (
parsed.scheme != "https"
or not parsed.hostname
or not parsed.hostname.lower().endswith(".slack.com")
or parsed.username
or parsed.password
or parsed.port is not None
or path_match is None
or path_match.group(1).upper() != target_channel_id
):
continue
packed_ts = path_match.group(2)
permalink_ts = f"{packed_ts[:-6]}.{packed_ts[-6:]}"
if permalink_ts != target_ts:
continue
permalink_thread_ts = (parse_qs(parsed.query).get("thread_ts") or [""])[0]
if re.fullmatch(r"\\d+\\.\\d{6}", permalink_thread_ts or ""):
thread_ts = permalink_thread_ts
except (TypeError, ValueError):
continue
if attachment.get("is_reply_unfurl") and not thread_ts:
logger.warning(
"[Slack] Refusing reply-unfurl file recovery without an exact thread root"
)
continue
try:
if thread_ts and thread_ts != target_ts:
response = await client.conversations_replies(
channel=target_channel_id,
ts=thread_ts,
oldest=target_ts,
latest=target_ts,
inclusive=True,
limit=1,
)
else:
response = await client.conversations_history(
channel=target_channel_id,
oldest=target_ts,
latest=target_ts,
inclusive=True,
limit=1,
)
except Exception as exc:
logger.warning(
"[Slack] Message-unfurl file recovery failed for %s: %s",
target_ts,
type(exc).__name__,
)
continue
linked_message = next(
(
message
for message in ((response or {}).get("messages") or [])
if isinstance(message, dict) and str(message.get("ts") or "") == target_ts
),
None,
)
if linked_message is None:
continue
for file_obj in linked_message.get("files") or []:
if not isinstance(file_obj, dict):
continue
file_id = str(file_obj.get("id") or "")
if re.fullmatch(r"F[A-Z0-9]{8,}", file_id) is None or file_id in seen_file_ids:
continue
seen_file_ids.add(file_id)
recovered.append(file_obj)
if len(recovered) >= 10:
return recovered
return recovered
`;
const MCP_META_HELPER = `
# ${HERMES_AGENT_BRIDGE_MARKER}: request-scoped Sellable MCP metadata.
def _sellable_agent_call_meta():
if os.getenv("SELLABLE_AGENT_RUNTIME", "") != "1":
return None
from gateway.session_context import get_session_env, session_context_engaged
if (
not session_context_engaged()
or get_session_env("HERMES_SESSION_PLATFORM", "").strip().lower() != "slack"
):
# Non-Slack runtime sessions (console/TUI, cron) carry no Slack actor
# identity. Send no actor meta; the serving API enforces its own actor
# gates, as with installs outside the Sellable runtime.
return None
from gateway.session_context import get_session_env, session_context_engaged
if not session_context_engaged():
raise RuntimeError("Sellable MCP calls require an active Hermes session context")
legacy_names = (
"HERMES_SESSION_PLATFORM",
"HERMES_SESSION_CHAT_ID",
"HERMES_SESSION_USER_ID",
"HERMES_SESSION_MESSAGE_ID",
)
if any(os.getenv(name) for name in legacy_names):
raise RuntimeError("Sellable MCP identity must not come from process-global session variables")
platform = get_session_env("HERMES_SESSION_PLATFORM", "").strip().lower()
channel_id = get_session_env("HERMES_SESSION_CHAT_ID", "").strip()
requester_id = get_session_env("HERMES_SESSION_USER_ID", "").strip()
message_id = get_session_env("HERMES_SESSION_MESSAGE_ID", "").strip()
session_id = get_session_env("HERMES_SESSION_ID", "").strip()
if platform != "slack" or not channel_id or not requester_id or not message_id or not session_id:
raise RuntimeError("Sellable MCP calls require a bound Slack requester, channel, message, and session")
return {
"sellableAgent": {
"requesterId": requester_id,
"channelId": channel_id,
"providerRequestId": message_id,
"sessionId": session_id,
}
}
`;
const MCP_META_HELPER_OPTIONAL_SESSION = MCP_META_HELPER.replace(
' if platform != "slack" or not channel_id or not requester_id or not message_id or not session_id:\n raise RuntimeError("Sellable MCP calls require a bound Slack requester, channel, message, and session")\n',
' if platform != "slack" or not channel_id or not requester_id or not message_id:\n raise RuntimeError("Sellable MCP calls require a bound Slack requester, channel, and message")\n'
).replace(
' return {\n "sellableAgent": {\n "requesterId": requester_id,\n "channelId": channel_id,\n "providerRequestId": message_id,\n "sessionId": session_id,\n }\n }\n',
' sellable_agent = {\n "requesterId": requester_id,\n "channelId": channel_id,\n "providerRequestId": message_id,\n }\n if session_id:\n sellable_agent["sessionId"] = session_id\n return {"sellableAgent": sellable_agent}\n'
);
const V020_SOUL_TURN_PROLOGUE_HELPER = `
# ${HERMES_AGENT_BRIDGE_MARKER}: apply only the proven live SOUL at a turn boundary.
_SELLABLE_AGENT_SOUL_SESSION_HASHES = {}
def _sellable_agent_restore_or_build_proven_soul(
agent,
system_message,
conversation_history,
restore_or_build_system_prompt,
):
import os
import re
if os.getenv("SELLABLE_AGENT_RUNTIME", "") != "1":
if agent._cached_system_prompt is None:
restore_or_build_system_prompt(agent, system_message, conversation_history)
return
import fcntl
import hashlib
import json
import stat
from pathlib import Path
from hermes_constants import get_hermes_home
profile_id = os.getenv("SELLABLE_HERMES_PROFILE_ID", "")
if re.fullmatch(r"[a-z0-9][a-z0-9_-]{0,127}", profile_id or "") is None:
raise RuntimeError("Sellable SOUL profile identity is unavailable or invalid")
data_root = Path("/opt/data")
expected_home = data_root / "profiles" / profile_id
try:
observed_home = Path(get_hermes_home())
observed_resolved = observed_home.resolve(strict=True)
expected_resolved = expected_home.resolve(strict=True)
if observed_resolved != expected_resolved:
# HERMES_HOME may legitimately be the data root (the directory
# that CONTAINS profiles/<id>) when no per-session override is
# active yet -- e.g. brand-new sessions in hermes serve. Accept
# it only when root/profiles/<profile_id> strictly resolves to
# the canonical profile directory.
if (
observed_home / "profiles" / profile_id
).resolve(strict=True) != expected_resolved:
raise RuntimeError("Hermes resolved a different SOUL profile")
except OSError as exc:
raise RuntimeError("Hermes SOUL profile cannot be resolved") from exc
lock_path = data_root / ".sellable-agent" / "soul-locks" / f"{profile_id}.lock"
marker_path = data_root / ".sellable-agent" / "soul-proofs" / f"{profile_id}.json"
state_root = data_root / ".sellable-agent"
state_directory_stats = []
for state_directory in (state_root, lock_path.parent, marker_path.parent):
try:
state_directory_stat = os.lstat(state_directory)
except OSError as exc:
raise RuntimeError("Sellable SOUL state directory is unavailable") from exc
if (
not stat.S_ISDIR(state_directory_stat.st_mode)
or state_directory_stat.st_uid != 0
or stat.S_IMODE(state_directory_stat.st_mode) != 0o2770
):
raise RuntimeError("Sellable SOUL state directory has unsafe metadata")
state_directory_stats.append(state_directory_stat)
state_gid = state_directory_stats[0].st_gid
if any(directory_stat.st_gid != state_gid for directory_stat in state_directory_stats[1:]):
raise RuntimeError("Sellable SOUL state directories have divergent groups")
allowed_owner_uids = {0, os.getuid()}
open_flags = os.O_RDWR | getattr(os, "O_CLOEXEC", 0) | getattr(os, "O_NOFOLLOW", 0)
try:
lock_fd = os.open(lock_path, open_flags)
except OSError as exc:
raise RuntimeError("Sellable SOUL lock is unavailable") from exc
try:
lock_stat = os.fstat(lock_fd)
if (
not stat.S_ISREG(lock_stat.st_mode)
or lock_stat.st_uid not in allowed_owner_uids
or lock_stat.st_gid != state_gid
or stat.S_IMODE(lock_stat.st_mode) != 0o660
or lock_stat.st_nlink != 1
):
raise RuntimeError("Sellable SOUL lock has unsafe metadata")
fcntl.flock(lock_fd, fcntl.LOCK_EX)
try:
marker_stat = os.lstat(marker_path)
if (
not stat.S_ISREG(marker_stat.st_mode)
or marker_stat.st_uid not in allowed_owner_uids
or marker_stat.st_gid != state_gid
or stat.S_IMODE(marker_stat.st_mode) != 0o660
or marker_stat.st_nlink != 1
or marker_stat.st_size <= 0
or marker_stat.st_size > 4096
):
raise RuntimeError("Sellable SOUL proof marker has unsafe metadata")
marker_flags = os.O_RDONLY | getattr(os, "O_CLOEXEC", 0) | getattr(os, "O_NOFOLLOW", 0)
marker_fd = os.open(marker_path, marker_flags)
try:
opened_marker_stat = os.fstat(marker_fd)
if (
opened_marker_stat.st_dev != marker_stat.st_dev
or opened_marker_stat.st_ino != marker_stat.st_ino
):
raise RuntimeError("Sellable SOUL proof marker changed while opening")
marker_chunks = []
marker_size = 0
while marker_size <= 4096:
marker_chunk = os.read(marker_fd, min(1024, 4097 - marker_size))
if not marker_chunk:
break
marker_chunks.append(marker_chunk)
marker_size += len(marker_chunk)
marker_bytes = b"".join(marker_chunks)
finally:
os.close(marker_fd)
if len(marker_bytes) > 4096 or len(marker_bytes) != marker_stat.st_size:
raise RuntimeError("Sellable SOUL proof marker exceeds its size limit")
marker = json.loads(marker_bytes.decode("utf-8"))
except (OSError, UnicodeDecodeError, ValueError) as exc:
raise RuntimeError("Sellable SOUL proof marker is unavailable or malformed") from exc
required_keys = {
"schemaVersion",
"state",
"profileId",
"rawFileSha256",
"effectiveSha256",
"generation",
}
if (
not isinstance(marker, dict)
or set(marker) != required_keys
or marker.get("schemaVersion") != "sellable-agent-soul-proof/v1"
or marker.get("state") != "PROVEN"
or marker.get("profileId") != profile_id
or re.fullmatch(r"[a-f0-9]{64}", marker.get("rawFileSha256") or "") is None
or re.fullmatch(r"[a-f0-9]{64}", marker.get("effectiveSha256") or "") is None
or not isinstance(marker.get("generation"), str)
or len(marker["generation"]) < 8
or len(marker["generation"]) > 128
):
marker_state = marker.get("state") if isinstance(marker, dict) else "invalid"
raise RuntimeError(
f"Sellable SOUL proof marker is not proven: path={marker_path} state={marker_state}"
)
soul_path = expected_home / "SOUL.md"
try:
soul_stat = os.lstat(soul_path)
if (
not stat.S_ISREG(soul_stat.st_mode)
or soul_stat.st_uid not in allowed_owner_uids
or stat.S_IMODE(soul_stat.st_mode) not in {0o600, 0o640}
or soul_stat.st_nlink != 1
):
raise RuntimeError("Hermes SOUL file has unsafe metadata")
soul_fd = os.open(
soul_path,
os.O_RDONLY | getattr(os, "O_CLOEXEC", 0) | getattr(os, "O_NOFOLLOW", 0),
)
try:
opened_soul_stat = os.fstat(soul_fd)
if (
opened_soul_stat.st_dev != soul_stat.st_dev
or opened_soul_stat.st_ino != soul_stat.st_ino
):
raise RuntimeError("Hermes SOUL file changed while opening")
soul_bytes = b""
while len(soul_bytes) <= 65536:
chunk = os.read(soul_fd, min(8192, 65537 - len(soul_bytes)))
if not chunk:
break
soul_bytes += chunk
finally:
os.close(soul_fd)
except OSError as exc:
raise RuntimeError("Hermes SOUL file cannot be read safely") from exc
if len(soul_bytes) > 65536:
raise RuntimeError("Hermes SOUL file exceeds its size limit")
raw_sha256 = hashlib.sha256(soul_bytes).hexdigest()
if raw_sha256 != marker["rawFileSha256"]:
raise RuntimeError("Hermes SOUL bytes are not the proven generation")
session_id = str(agent.session_id or "")
if not session_id:
raise RuntimeError("Hermes session identity is unavailable for SOUL refresh")
session_key = (profile_id, session_id)
if (
session_key not in _SELLABLE_AGENT_SOUL_SESSION_HASHES
and len(_SELLABLE_AGENT_SOUL_SESSION_HASHES) >= 4096
):
# A bounded cache miss only causes a safe one-time rebuild.
_SELLABLE_AGENT_SOUL_SESSION_HASHES.clear()
applied_sha256 = getattr(agent, "_sellable_soul_effective_sha256", None)
if applied_sha256 is None:
applied_sha256 = _SELLABLE_AGENT_SOUL_SESSION_HASHES.get(session_key)
soul_stale = applied_sha256 != marker["effectiveSha256"]
if soul_stale:
agent._cached_system_prompt = None
agent._cached_system_prompt_static = None
session_db = getattr(agent, "_session_db", None)
if session_db is None:
raise RuntimeError("Hermes session database is unavailable for SOUL refresh")
session_db.update_system_prompt(agent.session_id, None)
if agent._cached_system_prompt is None:
restore_or_build_system_prompt(agent, system_message, conversation_history)
if soul_stale:
from agent.prompt_builder import load_soul_md
effective_soul = load_soul_md()
effective_sha256 = hashlib.sha256(effective_soul.encode("utf-8")).hexdigest()
if effective_sha256 != marker["effectiveSha256"]:
agent._cached_system_prompt = None
agent._cached_system_prompt_static = None
raise RuntimeError("Hermes loader did not reproduce the proven SOUL")
if conversation_history:
# The upstream builder logs and continues on a DB write failure;
# a continuing Sellable session must fail closed instead.
session_db.update_system_prompt(
agent.session_id,
agent._cached_system_prompt,
)
applied_sha256 = effective_sha256
agent._sellable_soul_effective_sha256 = applied_sha256
_SELLABLE_AGENT_SOUL_SESSION_HASHES[session_key] = applied_sha256
finally:
try:
fcntl.flock(lock_fd, fcntl.LOCK_UN)
finally:
os.close(lock_fd)
`;
const MCP_ENDPOINT_META_HELPER = `
# ${HERMES_AGENT_BRIDGE_MARKER}: request-scoped Sellable MCP metadata.
def _sellable_agent_call_meta():
if os.getenv("SELLABLE_AGENT_RUNTIME", "") != "1":
return None
from gateway.session_context import get_session_env, session_context_engaged
if not session_context_engaged():
return None
legacy_names = (
"HERMES_SESSION_PLATFORM",
"HERMES_SESSION_CHAT_ID",
"HERMES_SESSION_USER_ID",
"HERMES_SESSION_MESSAGE_ID",
"HERMES_CRON_SESSION",
)
if any(os.getenv(name) for name in legacy_names):
raise RuntimeError("Sellable MCP identity must not come from process-global session variables")
platform = get_session_env("HERMES_SESSION_PLATFORM", "").strip().lower()
session_id = get_session_env("HERMES_SESSION_ID", "").strip()
if platform == "api_server":
if not session_id:
raise RuntimeError("Sellable endpoint MCP calls require a bound Hermes session")
return {"sellableEndpoint": {"sessionId": session_id}}
if not platform and get_session_env("HERMES_CRON_SESSION", "").strip() == "1":
# Native _CronRunScope clears human routing and sets this task-local flag
# (Phase207 ADMIN766 smoke). The API still enforces service/workspace gates.
return None
if platform != "slack":
descriptor_path = os.getenv("SELLABLE_AGENT_TURN_DESCRIPTOR_PATH", "")
if descriptor_path.startswith("/"):
# The downstream proxy validates and atomically consumes the signed
# endpoint principal, then retains that verified principal only for
# this stdio transport. The descriptor file is intentionally absent
# after the first tool call, so the configured absolute path rather
# than continued file existence is the bridge handoff contract.
# Hermes contributes no caller/model authority.
return None
raise RuntimeError("Sellable non-Slack MCP calls require a signed endpoint descriptor")
channel_id = get_session_env("HERMES_SESSION_CHAT_ID", "").strip()
requester_id = get_session_env("HERMES_SESSION_USER_ID", "").strip()
message_id = get_session_env("HERMES_SESSION_MESSAGE_ID", "").strip()
if not channel_id or not requester_id or not message_id or not session_id:
raise RuntimeError("Sellable MCP calls require a bound Slack requester, channel, message, and session")
return {
"sellableAgent": {
"requesterId": requester_id,
"channelId": channel_id,
"providerRequestId": message_id,
"sessionId": session_id,
}
}
`;
const MCP_ENDPOINT_META_HELPER_OPTIONAL_SESSION =
MCP_ENDPOINT_META_HELPER.replace(
' if not channel_id or not requester_id or not message_id or not session_id:\n raise RuntimeError("Sellable MCP calls require a bound Slack requester, channel, message, and session")\n',
' if not channel_id or not requester_id or not message_id:\n raise RuntimeError("Sellable MCP calls require a bound Slack requester, channel, and message")\n'
).replace(
' return {\n "sellableAgent": {\n "requesterId": requester_id,\n "channelId": channel_id,\n "providerRequestId": message_id,\n "sessionId": session_id,\n }\n }\n',
' sellable_agent = {\n "requesterId": requester_id,\n "channelId": channel_id,\n "providerRequestId": message_id,\n }\n if session_id:\n sellable_agent["sessionId"] = session_id\n return {"sellableAgent": sellable_agent}\n'
);
const CRON_MCP_ISOLATION_HELPER = `
# ${HERMES_AGENT_BRIDGE_MARKER}: cron sessions may use Sellable MCP toolsets.
import json as _sellable_agent_json
def _sellable_agent_strip_cron_mcp(toolsets, cfg):
# Pass-through, kept for injection-site stability: cron sessions carry no
# Slack actor meta and the serving API enforces its own actor gates.
return list(toolsets or [])
_SELLABLE_MANAGED_CUSTOMER_PROGRAM_JOBS = frozenset({
"sellable-default-campaign-daily-review",
"sellable-default-campaign-daily-results",
"sellable-default-campaign-weekly-review",
})
def _sellable_agent_validate_managed_wake_gate(job, script_path, prerun_script):
if str(job.get("name") or "") not in _SELLABLE_MANAGED_CUSTOMER_PROGRAM_JOBS:
return None, None
if not script_path:
return None, "managed wake gate script is missing"
if not isinstance(prerun_script, tuple) or len(prerun_script) != 2:
return None, "managed wake gate did not return a result"
ran_ok, output = prerun_script
if not ran_ok:
return None, "managed wake gate script failed"
lines = [line.strip() for line in str(output or "").splitlines() if line.strip()]
if not lines:
return None, "managed wake gate output is empty"
try:
value = _sellable_agent_json.loads(lines[-1])
except Exception:
return None, "managed wake gate output is malformed"
if not isinstance(value, dict) or not isinstance(value.get("wakeAgent"), bool):
return None, "managed wake gate output is malformed"
return value["wakeAgent"], None
def _sellable_agent_managed_gate_block(job_id, job_name, reason):
error = f"Sellable managed wake gate blocked before agent construction: {reason}"
doc = (
f"# Cron Job: {job_name}\\n\\n"
f"**Job ID:** {job_id}\\n"
"**Status:** BLOCKED\\n\\n"
f"{error}\\n"
)
return (False, doc, "", error), None
`;
const V019_ROOT_TOKEN_FILE_HELPER = `
# ${HERMES_AGENT_BRIDGE_MARKER}: root-owned Slack OAuth token-map gate.
_SELLABLE_AGENT_SLACK_TOKEN_FILE_SENTINEL = "__SELLABLE_ROOT_SLACK_TOKEN_FILE__"
def _sellable_agent_slack_token_source(env_value):
if os.getenv("SELLABLE_AGENT_RUNTIME", "") != "1":
return env_value
if env_value:
raise RuntimeError("SLACK_BOT_TOKEN must not be present in the Sellable runtime environment")
import stat
from hermes_constants import get_hermes_home
token_path = get_hermes_home() / "slack_tokens.json"
try:
token_stat = os.lstat(token_path)
except OSError as exc:
raise RuntimeError("root-owned Slack token map is unavailable") from exc
if (
not stat.S_ISREG(token_stat.st_mode)
or token_stat.st_uid != 0
or stat.S_IMODE(token_stat.st_mode) != 0o600
):
raise RuntimeError("root-owned Slack token map has unsafe ownership or mode")
return _SELLABLE_AGENT_SLACK_TOKEN_FILE_SENTINEL
`;
const V019_SLACK_MULTIPLEX_HELPER = `
# ${HERMES_AGENT_BRIDGE_MARKER}: exact Sellable Slack workspace ownership.
_SELLABLE_AGENT_SLACK_TOKEN_FILE_SENTINEL = "__SELLABLE_ROOT_SLACK_TOKEN_FILE__"
_SELLABLE_AGENT_INGRESS_CALLBACK_SHAPE = "sellable.slack.authorize-ingress/v1"
def _sellable_agent_load_slack_tokens(raw_token):
from hermes_constants import get_hermes_home
tokens_file = get_hermes_home() / "slack_tokens.json"
sellable_runtime = os.getenv("SELLABLE_AGENT_RUNTIME", "") == "1"
if not sellable_runtime:
bot_tokens = [t.strip() for t in raw_token.split(",") if t.strip()]
if tokens_file.exists():
try:
saved = json.loads(tokens_file.read_text(encoding="utf-8"))
for team_id, entry in saved.items():
tok = entry.get("token", "") if isinstance(entry, dict) else ""
if tok and tok not in bot_tokens:
bot_tokens.append(tok)
team_label = entry.get("team_name", team_id) if isinstance(entry, dict) else team_id
logger.info("[Slack] Loaded saved token for workspace %s", team_label)
except Exception as exc:
logger.warning("[Slack] Failed to read %s: %s", tokens_file, exc)
return bot_tokens, {}
if raw_token != _SELLABLE_AGENT_SLACK_TOKEN_FILE_SENTINEL:
raise RuntimeError("Sellable Slack bot credentials must come from the root-owned token map")
import stat
token_stat = os.lstat(tokens_file)
if (
not stat.S_ISREG(token_stat.st_mode)
or token_stat.st_uid != 0
or stat.S_IMODE(token_stat.st_mode) != 0o600
):
raise RuntimeError("root-owned Slack token map has unsafe ownership or mode")
saved = json.loads(tokens_file.read_text(encoding="utf-8"))
if not isinstance(saved, dict) or not saved:
raise RuntimeError("root-owned Slack token map is empty or malformed")
bot_tokens = []
token_owners = {}
for team_id, entry in sorted(saved.items()):
installation_id = entry.get("installationId", "") if isinstance(entry, dict) else ""
token = entry.get("token", "") if isinstance(entry, dict) else ""
if not team_id or not installation_id or not isinstance(token, str) or not token.startswith("xoxb-"):
raise RuntimeError("root-owned Slack token map contains an invalid installation")
prior = token_owners.get(token)
owner = {"teamId": str(team_id), "installationId": str(installation_id)}
if prior is not None and prior != owner:
raise RuntimeError("one Slack credential is claimed by divergent installations")
token_owners[token] = owner
if token not in bot_tokens:
bot_tokens.append(token)
return bot_tokens, token_owners
async def _sellable_agent_authorize_slack_route(adapter, team_id, channel_id, thread_id, actor_id):
callback = getattr(adapter, "_sellable_authorize_ingress", None)
callback_shape = getattr(adapter, "_sellable_authorize_ingress_shape", None)
installation_id = getattr(adapter, "_sellable_team_installation_ids", {}).get(team_id)
if callback_shape != _SELLABLE_AGENT_INGRESS_CALLBACK_SHAPE or not callable(callback):
raise RuntimeError("Sellable Slack ingress callback is unavailable or unsupported")
if not team_id or not installation_id or not channel_id or not actor_id:
raise RuntimeError("Sellable Slack ingress identity is incomplete")
principal = callback({
"teamId": str(team_id),
"installationId": str(installation_id),
"channelId": str(channel_id),
"threadId": str(thread_id) if thread_id else None,
"actorId": str(actor_id),
})
import inspect
if inspect.isawaitable(principal):
principal = await principal
required = ("teamId", "installationId", "channelId", "profileId", "revisionId")
if not isinstance(principal, dict) or any(not principal.get(key) for key in required):
raise RuntimeError("Sellable Slack ingress callback denied or returned an invalid principal")
if (
str(principal["teamId"]) != str(team_id)
or str(principal["installationId"]) != str(installation_id)
or str(principal["channelId"]) != str(channel_id)
or (principal.get("threadId") or None) != (str(thread_id) if thread_id else None)
):
raise RuntimeError("Sellable Slack ingress callback returned a mismatched principal")
from gateway.profile_routing import bind_sellable_slack_route_principal
return principal, bind_sellable_slack_route_principal(principal)
`;
const V019_PROFILE_ROUTING_HELPER = `
# ${HERMES_AGENT_BRIDGE_MARKER}: task-local exact Sellable route principal.
import contextvars as _sellable_contextvars
import os as _sellable_os
_sellable_slack_route_principal = _sellable_contextvars.ContextVar(
"sellable_slack_route_principal",
default=None,
)
def bind_sellable_slack_route_principal(principal):
if _sellable_os.getenv("SELLABLE_AGENT_RUNTIME", "") != "1":
raise RuntimeError("Sellable route binding is disabled outside the Sellable runtime")
return _sellable_slack_route_principal.set(principal)
def reset_sellable_slack_route_principal(token):
_sellable_slack_route_principal.reset(token)
`;
const V020_PROVIDER_PREFLIGHT_HELPER = `
# ${HERMES_AGENT_BRIDGE_MARKER}: bounded provider health before a gateway model turn.
_SELLABLE_AGENT_PROVIDER_PREFLIGHT_CACHE = {}
_SELLABLE_AGENT_PROVIDER_PREFLIGHT_LOCKS = {
"openai-codex": threading.Lock(),
"openrouter": threading.Lock(),
}
def _sellable_agent_preflight_float(env_name, default, minimum, maximum):
try:
value = float(os.getenv(env_name, str(default)))
except (TypeError, ValueError):
value = default
return max(minimum, min(maximum, value))
def _sellable_agent_preflight_failure(provider, entry):
import hashlib
import httpx
token = str(getattr(entry, "runtime_api_key", "") or "").strip()
if not token:
return 401, {
"reason": "sellable_provider_preflight_missing_credential",
"message": "Provider preflight found an empty runtime credential.",
}
timeout_seconds = _sellable_agent_preflight_float(
"SELLABLE_PROVIDER_PREFLIGHT_TIMEOUT_SECONDS", 1.5, 0.5, 5.0
)
cache_seconds = _sellable_agent_preflight_float(
"SELLABLE_PROVIDER_PREFLIGHT_CACHE_SECONDS", 30.0, 5.0, 300.0
)
fingerprint = hashlib.sha256(token.encode("utf-8")).hexdigest()
cache_key = (provider, str(getattr(entry, "id", "") or ""), fingerprint)
now = time.monotonic()
if _SELLABLE_AGENT_PROVIDER_PREFLIGHT_CACHE.get(cache_key, 0.0) > now:
return None
base_url = str(getattr(entry, "runtime_base_url", "") or "").strip().rstrip("/")
headers = {
"Authorization": "Bearer " + token,
"Accept": "application/json",
}
if provider == "openai-codex":
from hermes_cli.auth import _codex_usage_probe_url, _decode_jwt_claims
request_urls = {"usage": _codex_usage_probe_url(base_url)}
headers["User-Agent"] = "codex-cli"
try:
claims = _decode_jwt_claims(token)
auth_claims = claims.get("https://api.openai.com/auth") or {}
account_id = auth_claims.get("chatgpt_account_id")
if isinstance(account_id, str) and account_id.strip():
headers["ChatGPT-Account-Id"] = account_id.strip()
except Exception:
pass
else:
from hermes_constants import OPENROUTER_BASE_URL
openrouter_base_url = (base_url or OPENROUTER_BASE_URL).rstrip("/")
request_urls = {
"credits": openrouter_base_url + "/credits",
"key": openrouter_base_url + "/key",
}
try:
with httpx.Client(timeout=timeout_seconds) as client:
responses = {
name: client.get(url, headers=headers)
for name, url in request_urls.items()
}
except Exception as exc:
is_timeout = isinstance(exc, TimeoutError) or "timeout" in type(exc).__name__.lower()
return (408 if is_timeout else 503), {
"reason": (
"sellable_provider_preflight_timeout"
if is_timeout
else "sellable_provider_preflight_unreachable"
),
"message": "Provider preflight did not complete inside the bounded health window.",
"reset_at": time.time() + 30.0,
}
payloads = {}
for name, response in responses.items():
status_code = int(getattr(response, "status_code", 0) or 0)
if status_code < 200 or status_code >= 300:
transient = status_code == 0 or status_code >= 500
normalized_status = 503 if transient else status_code
context = {
"reason": "sellable_provider_preflight_http_rejected",
"message": "Provider preflight rejected the configured credential.",
}
retry_after = str(getattr(response, "headers", {}).get("Retry-After", "") or "")
try:
context["reset_at"] = time.time() + float(retry_after)
except (TypeError, ValueError):
if transient:
context["reset_at"] = time.time() + 30.0
return normalized_status, context
try:
payloads[name] = response.json() or {}
except Exception:
payloads[name] = {}
if provider == "openai-codex":
payload = payloads.get("usage") or {}
rate_limit = payload.get("rate_limit") or {}
exhausted_reset_times = []
exhausted = (
rate_limit.get("allowed") is False
or rate_limit.get("limit_reached") is True
)
for window_name in ("primary_window", "secondary_window"):
window = rate_limit.get(window_name) or {}
used_percent = window.get("used_percent")
if isinstance(used_percent, (int, float)) and float(used_percent) >= 100.0:
exhausted = True
if window.get("reset_at"):
exhausted_reset_times.append(window.get("reset_at"))
if exhausted:
context = {
"reason": "sellable_provider_preflight_quota_exhausted",
"message": "Codex usage health reports an exhausted account.",
}
if exhausted_reset_times:
# Every exhausted window must recover before the account is usable.
context["reset_at"] = max(exhausted_reset_times)
return 429, context
else:
credits_data = (payloads.get("credits") or {}).get("data") or {}
total_credits = credits_data.get("total_credits")
total_usage = credits_data.get("total_usage")
if (
isinstance(total_credits, (int, float))
and isinstance(total_usage, (int, float))
and float(total_credits) - float(total_usage) <= 0.0
):
return 402, {
"reason": "sellable_provider_preflight_credits_exhausted",
"message": "OpenRouter account health reports no remaining credits.",
}
key_data = (payloads.get("key") or {}).get("data") or {}
remaining = key_data.get("limit_remaining")
if isinstance(remaining, (int, float)) and float(remaining) <= 0.0:
context = {
"reason": "sellable_provider_preflight_quota_exhausted",
"message": "OpenRouter key health reports no remaining quota.",
}
if key_data.get("limit_reset"):
context["reset_at"] = key_data.get("limit_reset")
return 402, context
if len(_SELLABLE_AGENT_PROVIDER_PREFLIGHT_CACHE) >= 128:
_SELLABLE_AGENT_PROVIDER_PREFLIGHT_CACHE.clear()
_SELLABLE_AGENT_PROVIDER_PREFLIGHT_CACHE[cache_key] = time.monotonic() + cache_seconds
return None
def _sellable_agent_preflight_provider(provider):
if os.getenv("SELLABLE_AGENT_RUNTIME", "") != "1":
return
try:
from agent.credential_pool import load_pool
pool = load_pool(provider)
entry_count = len(pool.entries())
except Exception:
logger.warning("Sellable provider preflight could not load provider=%s", provider)
return
if entry_count == 0:
return
lock = _SELLABLE_AGENT_PROVIDER_PREFLIGHT_LOCKS[provider]
with lock:
attempted = set()
while len(attempted) < entry_count:
entry = pool.select()
if entry is None or entry.id in attempted:
break
attempted.add(entry.id)
failure = _sellable_agent_preflight_failure(provider, entry)
if failure is None:
return
status_code, error_context = failure
logger.warning(
"Sellable provider preflight skipped an unhealthy %s credential (%s)",
provider,
error_context.get("reason", "unknown"),
)
try:
pool.mark_exhausted_and_rotate(
status_code=status_code,
error_context=error_context,
credential_id=entry.id,
)
except Exception:
logger.warning(
"Sellable provider preflight could not persist provider=%s cooldown",
provider,
)
return
def _sellable_agent_preflight_model_providers():
if os.getenv("SELLABLE_AGENT_RUNTIME", "") != "1":
return
with concurrent.futures.ThreadPoolExecutor(
max_workers=2,
thread_name_prefix="sellable-provider-preflight",
) as executor:
futures = [
executor.submit(_sellable_agent_preflight_provider, provider)
for provider in ("openai-codex", "openrouter")
]
for future in futures:
try:
future.result()
except Exception:
logger.warning("Sellable provider preflight worker failed")
`;
export function patchHermesSourceFile(patchKind, source) {
if (typeof source !== "string") {
throw new HermesAgentBridgeError(
"HERMES_BRIDGE_INVALID_SOURCE",
"Hermes source must be UTF-8 text"
);
}
if (source.includes(HERMES_AGENT_BRIDGE_MARKER)) {
throw new HermesAgentBridgeError(
"HERMES_BRIDGE_ALREADY_PATCHED_SOURCE",
"Refusing to transform source that already contains the bridge marker",
{ patchKind }
);
}
if (patchKind === "api-opener-stage-v021") {
let patched = replaceExactlyOnce(
source,
"logger = logging.getLogger(__name__)\n",
`logger = logging.getLogger(__name__)\n
# ${HERMES_AGENT_BRIDGE_MARKER}: reserved, narrowing-only opener writer/editor sessions.
def _sellable_opener_output_format(model_options):
import hashlib
import json
options = model_options if isinstance(model_options, dict) else {}
if "sellable_opener_output_contract" not in options:
return None
contract = options["sellable_opener_output_contract"]
def reject():
raise RuntimeError("sellable_opener_output_contract_rejected")
if not isinstance(contract, dict) or set(contract) != {"schemaVersion", "schema", "nativeProposalSchemaDigest"}:
reject()
schema = contract["schema"]
if (
contract["schemaVersion"] != "sellable-opener-output-contract/v1"
or not isinstance(schema, dict)
or set(schema) != {"type", "additionalProperties", "required", "properties"}
or schema.get("type") != "object" or schema.get("additionalProperties") is not False
or schema.get("required") != ["proposal"]
or not isinstance(schema.get("properties"), dict) or set(schema["properties"]) != {"proposal"}
):
reject()
encoded = json.dumps(schema, sort_keys=True, separators=(",", ":"), ensure_ascii=False)
proposal = json.dumps(schema["properties"]["proposal"], sort_keys=True, separators=(",", ":"), ensure_ascii=False)
if len(encoded.encode()) > 32768 or hashlib.sha256(proposal.encode()).hexdigest() != contract["nativeProposalSchemaDigest"]:
reject()
return {"type": "json_schema", "name": "sellable_opener_proposal", "strict": True, "schema": schema}
def _sellable_opener_json_schema(output_format):
# Chat-completions spelling of the same strict format (OpenRouter response_format).
return {"type": "json_schema", "json_schema": {"name": output_format["name"], "strict": True, "schema": output_format["schema"]}}
def _sellable_opener_stage_kwargs(session_id, agent_kwargs, model_options=None):
import os
import re
runtime = os.getenv("SELLABLE_AGENT_RUNTIME", "") == "1"
stage = runtime and re.fullmatch(r"sellable_opener_stage_[a-f0-9]{32}", str(session_id or "")) is not None
endpoint = runtime and re.fullmatch(r"sellable_endpoint_[a-f0-9]{32}", str(session_id or "")) is not None
if stage:
agent_kwargs.update(
enabled_toolsets=[], skip_memory=True, skip_background_review=True,
skip_context_files=True, load_soul_identity=False, checkpoints_enabled=False,
)
output_format = _sellable_opener_output_format(model_options)
if output_format is not None:
overrides = dict(agent_kwargs.get("request_overrides") or {})
extra_body = dict(overrides.get("extra_body") or {})
if "text" in overrides or "text" in extra_body or "response_format" in overrides or "response_format" in extra_body:
raise RuntimeError("sellable_opener_output_format_conflict")
extra_body["text"] = {"format": output_format}
overrides["extra_body"] = extra_body
agent_kwargs.update(request_overrides=overrides, fallback_model=None)
elif endpoint and _sellable_opener_output_format(model_options) is not None:
# A per-run model's endpoint session keeps its tools; only its output
# is held to the strict schema, routed to providers that enforce it.
output_format = _sellable_opener_output_format(model_options)
overrides = dict(agent_kwargs.get("request_overrides") or {})
extra_body = dict(overrides.get("extra_body") or {})
if "text" in overrides or "text" in extra_body or "response_format" in overrides or "response_format" in extra_body:
raise RuntimeError("sellable_opener_output_format_conflict")
extra_body["response_format"] = _sellable_opener_json_schema(output_format)
overrides["extra_body"] = extra_body
agent_kwargs.update(request_overrides=overrides, fallback_model=None, provider_require_parameters=True)
elif isinstance(model_options, dict) and "sellable_opener_output_contract" in model_options:
raise RuntimeError("sellable_opener_output_contract_session_rejected")
return stage
def _sellable_assert_opener_stage_tools(stage, agent, model_options=None):
if stage and (agent.tools or agent.valid_tool_names):
raise RuntimeError("sellable_opener_stage_tools_not_empty")
output_format = _sellable_opener_output_format(model_options)
if output_format is None:
return
import copy
if stage:
if agent.api_mode != "codex_responses" or agent.provider != "openai-codex" or agent._fallback_chain:
raise RuntimeError("sellable_opener_output_format_unsupported")
expected_key, expected_value = "text", {"format": copy.deepcopy(output_format)}
else:
if agent.api_mode != "chat_completions" or agent.provider != "openrouter" or agent._fallback_chain:
raise RuntimeError("sellable_opener_output_format_unsupported")
expected_key, expected_value = "response_format", _sellable_opener_json_schema(copy.deepcopy(output_format))
selected = (agent.model, agent.provider, agent.api_mode)
build_api_kwargs = agent._build_api_kwargs
def strict_build_api_kwargs(*args, **kwargs):
built = build_api_kwargs(*args, **kwargs)
extra_body = built.get("extra_body") or {}
if (
(agent.model, agent.provider, agent.api_mode) != selected or agent._fallback_chain
or extra_body.get(expected_key) != expected_value
or (not stage and (extra_body.get("provider") or {}).get("require_parameters") is not True)
):
raise RuntimeError("sellable_opener_output_format_not_enforced")
return built
agent._build_api_kwargs = strict_build_api_kwargs
`,
"v0.21 isolated opener stage helpers"
);
patched = replaceExactlyOnce(
patched,
" agent = AIAgent(**agent_kwargs)\n",
" _sellable_opener_stage = _sellable_opener_stage_kwargs(session_id, agent_kwargs, model_options)\n agent = AIAgent(**agent_kwargs)\n _sellable_assert_opener_stage_tools(_sellable_opener_stage, agent, model_options)\n",
"v0.21 isolated opener agent construction"
);
return patched;
}
// Hermes 0.21 split configuration, MCP dispatch, and turn execution into
// separate modules. Keep the historical contracts intact for older images.
if (patchKind === "gateway-first-contact-v0213") {
return replaceExactlyOnce(
source,
` if not await self.async_session_store.has_any_sessions():
_intro_note = (
"[System note: This is the user's very first message ever. "
"Briefly introduce yourself and mention that /help shows available commands. "
"Keep the introduction concise -- one or two sentences max.]"
)
# onboarding.profile_build == "ask" (default) and not yet offered: swap the plain intro for
# a consent-gated profile-build directive. Fires at most once.
try:
from agent.onboarding import (
PROFILE_BUILD_FLAG, is_seen, mark_seen, profile_build_directive,
profile_build_mode,
)
_onb_cfg = _load_gateway_config()
if profile_build_mode(_onb_cfg) == "ask" and not is_seen(_onb_cfg, PROFILE_BUILD_FLAG):
turn_sidecar_notes.append(profile_build_directive().strip())
mark_seen(_hermes_home / "config.yaml", PROFILE_BUILD_FLAG)
else:
turn_sidecar_notes.append(_intro_note)
except Exception as _pb_err:
logger.debug("Profile-build onboarding directive failed, using plain intro: %s", _pb_err)
turn_sidecar_notes.append(_intro_note)`,
` # ${HERMES_AGENT_BRIDGE_MARKER}: Sellable owns the hosted welcome and
# must receive the customer's first request unchanged.
_gateway_config = {}
with suppress(Exception):
_loaded_gateway_config = _load_gateway_config()
if isinstance(_loaded_gateway_config, dict):
_gateway_config = _loaded_gateway_config
_onboarding_config = _gateway_config.get("onboarding")
_sellable_managed_welcome = (
isinstance(_onboarding_config, dict)
and _onboarding_config.get("sellable_managed_welcome") is True
)
if (
not _sellable_managed_welcome
and not await self.async_session_store.has_any_sessions()
):
_intro_note = (
"[System note: This is the user's very first message ever. "
"Briefly introduce yourself and mention that /help shows available commands. "
"Keep the introduction concise -- one or two sentences max.]"
)
# onboarding.profile_build == "ask" (default) and not yet offered: swap the plain intro for
# a consent-gated profile-build directive. Fires at most once.
try:
from agent.onboarding import (
PROFILE_BUILD_FLAG, is_seen, mark_seen, profile_build_directive,
profile_build_mode,
)
_onb_cfg = _gateway_config
if profile_build_mode(_onb_cfg) == "ask" and not is_seen(_onb_cfg, PROFILE_BUILD_FLAG):
turn_sidecar_notes.append(profile_build_directive().strip())
mark_seen(_hermes_home / "config.yaml", PROFILE_BUILD_FLAG)
else:
turn_sidecar_notes.append(_intro_note)
except Exception as _pb_err:
logger.debug("Profile-build onboarding directive failed, using plain intro: %s", _pb_err)
turn_sidecar_notes.append(_intro_note)`,
"v0.21.3 Sellable-managed first contact"
);
}
if (patchKind === "gateway-config-dedicated-v021") {
return replaceExactlyOnce(
source,
"getenv = _getenv_str\n",
`${SECRET_FD_HELPER}
def getenv(name, default=""):
if name == "SLACK_BOT_TOKEN" and os.getenv("SELLABLE_AGENT_RUNTIME", "") == "1":
return _sellable_agent_read_slack_secret(9, "SLACK_BOT_TOKEN", "xoxb-")
return _getenv_str(name, default)
`,
"v0.21 dedicated config credential reader"
);
}
if (
patchKind === "slack-adapter-dedicated-v021" ||
patchKind === "slack-adapter-dedicated-v0213"
) {
// v0.21.3 moved credential lookup into a profile-scoped helper. Preserve
// that upstream isolation outside the dedicated Sellable runtime.
const scopedCredential = patchKind === "slack-adapter-dedicated-v0213";
let patched = replaceExactlyOnce(
source,
"logger = logging.getLogger(__name__)\n",
`logger = logging.getLogger(__name__)\n${SECRET_FD_HELPER}${SLACK_DEDICATED_TEST_API_HELPER}${SLACK_MESSAGE_UNFURL_FILE_HELPER}`,
"v0.21 dedicated Slack helpers"
);
patched = replaceExactlyOnce(
patched,
scopedCredential
? ' app_token = _get_scoped_secret("SLACK_APP_TOKEN")'
: ' app_token = get_secret("SLACK_APP_TOKEN")',
scopedCredential
? ' app_token = (_sellable_agent_read_slack_secret(8, "SLACK_APP_TOKEN", "xapp-")\n if os.getenv("SELLABLE_AGENT_RUNTIME", "") == "1"\n else _get_scoped_secret("SLACK_APP_TOKEN"))'
: ' app_token = (_sellable_agent_read_slack_secret(8, "SLACK_APP_TOKEN", "xapp-")\n if os.getenv("SELLABLE_AGENT_RUNTIME", "") == "1"\n else get_secret("SLACK_APP_TOKEN"))',
"v0.21 dedicated app credential"
);
patched = replaceExactlyOnce(
patched,
" client = AsyncWebClient(token=token, user_agent_prefix=_HERMES_SLACK_USER_AGENT_PREFIX)",
" client = AsyncWebClient(token=token, user_agent_prefix=_HERMES_SLACK_USER_AGENT_PREFIX,\n **_sellable_agent_slack_api_kwargs())",
"v0.21 Slack API client"
);
patched = replaceExactlyOnce(
patched,
" present = tokens_file.exists()",
' present = tokens_file.exists() and os.getenv("SELLABLE_AGENT_RUNTIME", "") != "1"',
"v0.21 OAuth file isolation"
);
patched = replaceExactlyOnce(
patched,
scopedCredential
? " scope_id=str(team_id) if team_id else None,\n message_id=ts,\n # Workflow/app posts"
: " scope_id=str(team_id) if team_id else None,\n # Workflow/app posts",
" scope_id=str(team_id) if team_id else None,\n message_id=ts,\n # Workflow/app posts",
"v0.21 Slack source identity"
);
return replaceExactlyOnce(
patched,
' for f in event.get("files", []):',
[
' files = list(event.get("files") or [])',
" files.extend(await _sellable_agent_recover_slack_message_unfurl_files(",
' self, event.get("attachments") or [], channel_id, team_id, files))',
" for f in files:",
].join("\n"),
"v0.21 unfurled file recovery"
);
}
if (patchKind === "mcp-tool-endpoint-v021") {
let patched = replaceExactlyOnce(
source,
'logger = logging.getLogger("tools.mcp_tool")\n',
`logger = logging.getLogger("tools.mcp_tool")\nimport os\n${MCP_ENDPOINT_META_HELPER_OPTIONAL_SESSION}`,
"v0.21 MCP metadata helper"
);
return replaceExactlyOnce(
patched,
" _call_coro = server.session.call_tool(tool_name, arguments=args)",
[
" sellable_meta = _sellable_agent_call_meta()",
' call_kwargs = {"arguments": args}',
" if sellable_meta is not None:",
' call_kwargs["meta"] = sellable_meta',
" _call_coro = server.session.call_tool(tool_name, **call_kwargs)",
].join("\n"),
"v0.21 MCP call metadata"
);
}
if (patchKind === "gateway-session-v021") {
return replaceExactlyOnce(
source,
" session_key=context.session_key,\n",
` # ${HERMES_AGENT_BRIDGE_MARKER}: durable conversation identity.
session_key=context.session_key,
session_id=context.session_id,
`,
"v0.21 durable session identity"
);
}
if (patchKind === "gateway-provider-preflight-v021") {
let patched = replaceExactlyOnce(
source,
'logger = logging.getLogger("gateway.run")\n',
`logger = logging.getLogger("gateway.run")\nimport os\nimport concurrent.futures\n${V020_PROVIDER_PREFLIGHT_HELPER}`,
"v0.21 provider helper"
);
return replaceExactlyOnce(
patched,
" max_iterations = _current_max_iterations()\n",
" max_iterations = _current_max_iterations()\n _sellable_agent_preflight_model_providers()\n",
"v0.21 provider preflight"
);
}
if (patchKind === "turn-context-v021") {
const openerIsolatedSoulHelper = V020_SOUL_TURN_PROLOGUE_HELPER.replace(
" import fcntl\n",
` # Opener stages carry their complete frozen policy/facts in the request.
# Do not read profile SOUL/memory while constructing this isolated turn.
if re.fullmatch(r"sellable_opener_stage_[a-f0-9]{32}", str(getattr(agent, "session_id", ""))) is not None:
if (
getattr(agent, "skip_context_files", False) is not True
or getattr(agent, "load_soul_identity", True) is not False
or getattr(agent, "tools", None) != []
or getattr(agent, "valid_tool_names", None) != set()
):
raise RuntimeError("sellable_opener_stage_context_not_isolated")
if agent._cached_system_prompt is None:
restore_or_build_system_prompt(agent, system_message, conversation_history)
return
import fcntl\n`
);
let patched = replaceExactlyOnce(
source,
"logger = logging.getLogger(__name__)\n",
`logger = logging.getLogger(__name__)\n${openerIsolatedSoulHelper}`,
"v0.21 SOUL helper"
);
return replaceExactlyOnce(
patched,
" # System prompt is cached per session for prefix caching.\n if agent._cached_system_prompt is None:\n restore_or_build_system_prompt(agent, system_message, conversation_history)",
" # System prompt is cached per session for prefix caching.\n _sellable_agent_restore_or_build_proven_soul(\n agent, system_message, conversation_history, restore_or_build_system_prompt,\n )",
"v0.21 SOUL turn boundary"
);
}
if (patchKind === "gateway-config") {
let patched = replaceExactlyOnce(
source,
"logger = logging.getLogger(__name__)\n",
`logger = logging.getLogger(__name__)\n${SECRET_FD_HELPER}${SLACK_TEST_API_HELPER}`,
"gateway helper"
);
patched = replaceExactlyOnce(
patched,
' slack_token = os.getenv("SLACK_BOT_TOKEN")',
' slack_token = _sellable_agent_read_slack_secret(9, "SLACK_BOT_TOKEN", "xoxb-")',
"Slack bot token"
);
return patched;
}
if (patchKind === "gateway-config-v019") {
let patched = replaceExactlyOnce(
source,
"logger = logging.getLogger(__name__)\n",
`logger = logging.getLogger(__name__)\n${V019_ROOT_TOKEN_FILE_HELPER}`,
"v0.19 gateway token-map helper"
);
patched = replaceExactlyOnce(
patched,
' slack_token = getenv("SLACK_BOT_TOKEN")',
' slack_token = _sellable_agent_slack_token_source(getenv("SLACK_BOT_TOKEN"))',
"v0.19 Slack bot token source"
);
return patched;
}
if (patchKind === "gateway-config-dedicated-v019") {
let patched = replaceExactlyOnce(
source,
"logger = logging.getLogger(__name__)\n",
`logger = logging.getLogger(__name__)\n${SECRET_FD_HELPER}`,
"v0.19 dedicated gateway helper"
);
patched = replaceExactlyOnce(
patched,
' slack_token = getenv("SLACK_BOT_TOKEN")',
' slack_token = _sellable_agent_read_slack_secret(9, "SLACK_BOT_TOKEN", "xoxb-")',
"v0.19 dedicated Slack bot token"
);
return patched;
}
if (patchKind === "slack-adapter") {
let patched = replaceExactlyOnce(
source,
"logger = logging.getLogger(__name__)\n",
`logger = logging.getLogger(__name__)\n${SECRET_FD_HELPER}`,
"Slack adapter helper"
);
patched = replaceExactlyOnce(
patched,
' app_token = os.getenv("SLACK_APP_TOKEN")',
' app_token = _sellable_agent_read_slack_secret(8, "SLACK_APP_TOKEN", "xapp-")',
"Slack app token"
);
patched = replaceExactlyOnce(
patched,
' tokens_file = get_hermes_home() / "slack_tokens.json"\n if tokens_file.exists():',
' tokens_file = get_hermes_home() / "slack_tokens.json"\n if tokens_file.exists() and os.getenv("SELLABLE_AGENT_RUNTIME", "") != "1":',
"legacy Slack token file"
);
return patched;
}
if (patchKind === "slack-adapter-v019") {
let patched = replaceExactlyOnce(
source,
"logger = logging.getLogger(__name__)\n",
`logger = logging.getLogger(__name__)\n${SECRET_FD_HELPER}${V019_SLACK_MULTIPLEX_HELPER}`,
"v0.19 Slack multiplex helper"
);
patched = replaceExactlyOnce(
patched,
[
" except UnscopedSecretError:",
' app_token = os.getenv("SLACK_APP_TOKEN")',
].join("\n"),
[
" except UnscopedSecretError:",
' app_token = _sellable_agent_read_slack_secret(8, "SLACK_APP_TOKEN", "xapp-")',
].join("\n"),
"v0.19 Slack app token"
);
patched = replaceExactlyOnce(
patched,
[
" # Support comma-separated bot tokens for multi-workspace",
' bot_tokens = [t.strip() for t in raw_token.split(",") if t.strip()]',
"",
" # Also load tokens from OAuth token file",
" from hermes_constants import get_hermes_home",
"",
' tokens_file = get_hermes_home() / "slack_tokens.json"',
" if tokens_file.exists():",
" try:",
' saved = json.loads(tokens_file.read_text(encoding="utf-8"))',
" for team_id, entry in saved.items():",
' tok = entry.get("token", "") if isinstance(entry, dict) else ""',
" if tok and tok not in bot_tokens:",
" bot_tokens.append(tok)",
" team_label = (",
' entry.get("team_name", team_id)',
" if isinstance(entry, dict)",
" else team_id",
" )",
" logger.info(",
' "[Slack] Loaded saved token for workspace %s", team_label',
" )",
" except Exception as e:",
' logger.warning("[Slack] Failed to read %s: %s", tokens_file, e)',
].join("\n"),
" bot_tokens, _sellable_token_owners = _sellable_agent_load_slack_tokens(raw_token)",
"v0.19 Slack OAuth token inputs"
);
patched = replaceExactlyOnce(
patched,
[
" self._team_clients = {}",
" self._team_bot_user_ids = {}",
].join("\n"),
[
" self._team_clients = {}",
" self._team_bot_user_ids = {}",
" self._sellable_team_installation_ids = {}",
].join("\n"),
"v0.19 Slack installation map reset"
);
patched = replaceExactlyOnce(
patched,
[
' team_name = auth_response.get("team", "unknown")',
"",
" self._team_clients[team_id] = client",
].join("\n"),
[
' team_name = auth_response.get("team", "unknown")',
"",
' if os.getenv("SELLABLE_AGENT_RUNTIME", "") == "1":',
" owner = _sellable_token_owners.get(token)",
' bot_id = auth_response.get("bot_id", "")',
' if not owner or owner["teamId"] != team_id or not bot_user_id or not bot_id:',
' raise RuntimeError("Slack OAuth token authenticated to an unexpected team or principal")',
" prior_installation = self._sellable_team_installation_ids.get(team_id)",
' if prior_installation and prior_installation != owner["installationId"]:',
' raise RuntimeError("Slack team has divergent installation ownership")',
' self._sellable_team_installation_ids[team_id] = owner["installationId"]',
"",
" self._team_clients[team_id] = client",
].join("\n"),
"v0.19 Slack authenticated installation binding"
);
patched = replaceExactlyOnce(
patched,
[
" def _get_client(self, chat_id: str, team_id: Optional[str] = None) -> Any:",
' """Return the workspace-specific WebClient for a channel."""',
" if team_id and team_id in self._team_clients:",
" return self._team_clients[team_id]",
" team_id = self._channel_team.get(chat_id)",
" if team_id and team_id in self._team_clients:",
" return self._team_clients[team_id]",
" return self._app.client # fallback to primary",
].join("\n"),
[
" def _get_client(self, chat_id: str, team_id: Optional[str] = None) -> Any:",
' """Return the workspace-specific WebClient for a channel."""',
' if os.getenv("SELLABLE_AGENT_RUNTIME", "") == "1":',
' installation_id = getattr(self, "_sellable_team_installation_ids", {}).get(team_id)',
" client = self._team_clients.get(team_id) if team_id else None",
" if not team_id or not installation_id or client is None:",
' raise RuntimeError("exact Slack workspace client is unavailable")',
" return client",
" if team_id and team_id in self._team_clients:",
" return self._team_clients[team_id]",
" team_id = self._channel_team.get(chat_id)",
" if team_id and team_id in self._team_clients:",
" return self._team_clients[team_id]",
" return self._app.client # fallback to primary",
].join("\n"),
"v0.19 exact Slack egress client"
);
patched = replaceExactlyOnce(
patched,
" # Build source\n source = self.build_source(",
[
" # Sellable admission runs before native profile resolution and any Agent/session work.",
" _sellable_principal = None",
" _sellable_route_token = None",
' if os.getenv("SELLABLE_AGENT_RUNTIME", "") == "1":',
" _sellable_principal, _sellable_route_token = await _sellable_agent_authorize_slack_route(",
" self, team_id, channel_id, thread_ts, user_id",
" )",
" try:",
" source = self.build_source(",
].join("\n"),
"v0.19 pre-resolution Slack admission"
);
patched = replaceExactlyOnce(
patched,
[
' is_bot=bool(event.get("bot_id")) or event.get("subtype") == "bot_message",',
" )",
"",
" # Per-channel ephemeral prompt",
].join("\n"),
[
' is_bot=bool(event.get("bot_id")) or event.get("subtype") == "bot_message",',
" )",
" finally:",
" if _sellable_route_token is not None:",
" from gateway.profile_routing import reset_sellable_slack_route_principal",
" reset_sellable_slack_route_principal(_sellable_route_token)",
' if _sellable_principal is not None and source.profile != _sellable_principal["profileId"]:',
' raise RuntimeError("Sellable Slack profile resolution did not preserve the exact principal")',
"",
" # Per-channel ephemeral prompt",
].join("\n"),
"v0.19 post-resolution Slack principal check"
);
return patched;
}
if (patchKind === "slack-adapter-dedicated-v019") {
let patched = replaceExactlyOnce(
source,
"logger = logging.getLogger(__name__)\n",
`logger = logging.getLogger(__name__)\n${SECRET_FD_HELPER}${SLACK_DEDICATED_TEST_API_HELPER}${SLACK_MESSAGE_UNFURL_FILE_HELPER}`,
"v0.19 dedicated Slack helper"
);
patched = replaceExactlyOnce(
patched,
[
" try:",
' app_token = get_secret("SLACK_APP_TOKEN")',
" except UnscopedSecretError:",
' app_token = os.getenv("SLACK_APP_TOKEN")',
].join("\n"),
[
' if os.getenv("SELLABLE_AGENT_RUNTIME", "") == "1":',
' app_token = _sellable_agent_read_slack_secret(8, "SLACK_APP_TOKEN", "xapp-")',
" else:",
" try:",
' app_token = get_secret("SLACK_APP_TOKEN")',
" except UnscopedSecretError:",
' app_token = os.getenv("SLACK_APP_TOKEN")',
].join("\n"),
"v0.19 dedicated Slack app token"
);
patched = replaceExactlyOnce(
patched,
[
" primary_client = AsyncWebClient(",
" token=primary_token,",
" user_agent_prefix=_HERMES_SLACK_USER_AGENT_PREFIX,",
" )",
].join("\n"),
[
" primary_client = AsyncWebClient(",
" token=primary_token,",
" user_agent_prefix=_HERMES_SLACK_USER_AGENT_PREFIX,",
" **_sellable_agent_slack_api_kwargs(),",
" )",
].join("\n"),
"v0.19 dedicated Slack app API client"
);
patched = replaceExactlyOnce(
patched,
[
" client = AsyncWebClient(",
" token=token,",
" user_agent_prefix=_HERMES_SLACK_USER_AGENT_PREFIX,",
" )",
].join("\n"),
[
" client = AsyncWebClient(",
" token=token,",
" user_agent_prefix=_HERMES_SLACK_USER_AGENT_PREFIX,",
" **_sellable_agent_slack_api_kwargs(),",
" )",
].join("\n"),
"v0.19 dedicated Slack workspace API client"
);
patched = replaceExactlyOnce(
patched,
" if tokens_file.exists():",
' if tokens_file.exists() and os.getenv("SELLABLE_AGENT_RUNTIME", "") != "1":',
"v0.19 dedicated Slack OAuth token file"
);
patched = replaceExactlyOnce(
patched,
[
" scope_id=str(team_id) if team_id else None,",
" # Slack Workflow Builder / app posts arrive as",
].join("\n"),
[
" scope_id=str(team_id) if team_id else None,",
" # Preserve Hermes' native Slack message identity in task-local context.",
" message_id=ts,",
" # Slack Workflow Builder / app posts arrive as",
].join("\n"),
"v0.19 dedicated Slack request identity"
);
patched = replaceExactlyOnce(
patched,
' files = event.get("files", [])',
[
' files = list(event.get("files") or [])',
" files.extend(",
" await _sellable_agent_recover_slack_message_unfurl_files(",
" self, slack_attachments, channel_id, team_id, files",
" )",
" )",
].join("\n"),
"v0.19 dedicated Slack message-unfurl files"
);
return patched;
}
if (patchKind === "profile-routing-v019") {
let patched = replaceExactlyOnce(
source,
"logger = logging.getLogger(__name__)\n",
`logger = logging.getLogger(__name__)\n${V019_PROFILE_ROUTING_HELPER}`,
"v0.19 profile route principal helper"
);
patched = replaceExactlyOnce(
patched,
' """Return the best-matching route, or None for no match."""\n for route in routes:',
[
' """Return the best-matching route, or None for no match."""',
' if _sellable_os.getenv("SELLABLE_AGENT_RUNTIME", "") == "1":',
" principal = _sellable_slack_route_principal.get()",
' if not isinstance(principal, dict) or not principal.get("profileId"):',
' raise RuntimeError("exact Sellable Slack route principal is unavailable")',
" return ProfileRoute(",
' name="sellable-exact-route",',
" platform=str(platform),",
' profile=str(principal["profileId"]),',
" chat_id=str(chat_id) if chat_id else None,",
" thread_id=str(thread_id) if thread_id else None,",
" )",
" for route in routes:",
].join("\n"),
"v0.19 exact profile route selection"
);
return patched;
}
if (
patchKind === "mcp-tool" ||
patchKind === "mcp-tool-v020" ||
patchKind === "mcp-tool-endpoint-v020"
) {
const metaHelper =
patchKind === "mcp-tool-endpoint-v020"
? MCP_ENDPOINT_META_HELPER_OPTIONAL_SESSION
: patchKind === "mcp-tool-v020"
? MCP_META_HELPER_OPTIONAL_SESSION
: MCP_META_HELPER;
let patched = replaceExactlyOnce(
source,
"logger = logging.getLogger(__name__)\n",
`logger = logging.getLogger(__name__)\n${metaHelper}`,
"MCP metadata helper"
);
patched = replaceExactlyOnce(
patched,
" result = await server.session.call_tool(tool_name, arguments=args)",
[
" sellable_meta = _sellable_agent_call_meta()",
' call_kwargs = {"arguments": args}',
" if sellable_meta is not None:",
' call_kwargs["meta"] = sellable_meta',
" result = await server.session.call_tool(tool_name, **call_kwargs)",
].join("\n"),
"MCP call metadata"
);
return patched;
}
if (patchKind === "gateway-session-v020") {
let patched = replaceExactlyOnce(
source,
"logger = logging.getLogger(__name__)\n",
`logger = logging.getLogger(__name__)\n${V020_PROVIDER_PREFLIGHT_HELPER}`,
"v0.20 provider preflight helper"
);
patched = replaceExactlyOnce(
patched,
[
" session_key=context.session_key,",
' message_id=str(context.source.message_id) if context.source.message_id else "",',
].join("\n"),
[
" session_key=context.session_key,",
" # Bind the durable Hermes conversation ID alongside the Slack actor.",
" # Sellable MCP SOUL calls require this task-local identity, and omitting",
" # it must not make otherwise valid Slack MCP calls fail closed.",
" session_id=context.session_id,",
' message_id=str(context.source.message_id) if context.source.message_id else "",',
].join("\n"),
"v0.20 gateway durable session identity"
);
patched = replaceExactlyOnce(
patched,
[
" max_iterations = _current_max_iterations()",
"",
" try:",
" model, runtime_kwargs = self._runner._resolve_session_agent_runtime(",
].join("\n"),
[
" max_iterations = _current_max_iterations()",
"",
" _sellable_agent_preflight_model_providers()",
"",
" try:",
" model, runtime_kwargs = self._runner._resolve_session_agent_runtime(",
].join("\n"),
"v0.20 gateway provider preflight invocation"
);
return patched;
}
if (patchKind === "clarify-session-key-v020") {
return replaceExactlyOnce(
source,
[
" session_key = build_session_key(",
" event.source,",
' group_sessions_per_user=self.config.extra.get("group_sessions_per_user", True),',
' thread_sessions_per_user=self.config.extra.get("thread_sessions_per_user", False),',
" )",
].join("\n"),
[
' _sk_store = getattr(self, "_session_store", None)',
" session_key = build_session_key(",
" event.source,",
' group_sessions_per_user=self.config.extra.get("group_sessions_per_user", True),',
' thread_sessions_per_user=self.config.extra.get("thread_sessions_per_user", False),',
" profile=_sk_store._resolve_profile_for_key(event.source) if _sk_store else None,",
" )",
].join("\n"),
"v0.20 profile-scoped clarify session key"
);
}
if (patchKind === "turn-context-v020") {
let patched = replaceExactlyOnce(
source,
"logger = logging.getLogger(__name__)\n",
`logger = logging.getLogger(__name__)\n${V020_SOUL_TURN_PROLOGUE_HELPER}`,
"v0.20 SOUL turn-prologue helper"
);
patched = replaceExactlyOnce(
patched,
[
" # ── System prompt (cached per session for prefix caching) ──",
" if agent._cached_system_prompt is None:",
" restore_or_build_system_prompt(agent, system_message, conversation_history)",
].join("\n"),
[
" # ── System prompt (cached per session for prefix caching) ──",
" _sellable_agent_restore_or_build_proven_soul(",
" agent,",
" system_message,",
" conversation_history,",
" restore_or_build_system_prompt,",
" )",
].join("\n"),
"v0.20 SOUL turn-prologue call"
);
return patched;
}
if (patchKind === "cron-scheduler-v020") {
let patched = replaceExactlyOnce(
source,
"logger = logging.getLogger(__name__)\n",
`logger = logging.getLogger(__name__)\n${CRON_MCP_ISOLATION_HELPER}`,
"v0.20 cron MCP isolation helper"
);
patched = replaceExactlyOnce(
patched,
" return _merge_mcp_into_per_job_toolsets(list(per_job), cfg or {})",
" return _sellable_agent_strip_cron_mcp(\n _merge_mcp_into_per_job_toolsets(list(per_job), cfg or {}), cfg or {}\n )",
"v0.20 per-job cron MCP isolation"
);
patched = replaceExactlyOnce(
patched,
' return sorted(_get_platform_tools(cfg or {}, "cron"))',
' return _sellable_agent_strip_cron_mcp(\n sorted(_get_platform_tools(cfg or {}, "cron")), cfg or {}\n )',
"v0.20 platform cron MCP isolation"
);
if (patched.includes("def _prepare_job_prompt(")) {
patched = replaceExactlyOnce(
patched,
[
" prerun_script = None",
' script_path = job.get("script")',
" if script_path:",
].join("\n"),
[
" prerun_script = None",
' script_path = job.get("script")',
" if (",
' str(job.get("name") or "") in _SELLABLE_MANAGED_CUSTOMER_PROGRAM_JOBS',
" and not script_path",
" ):",
" return _sellable_agent_managed_gate_block(",
' job_id, job_name, "managed wake gate script is missing"',
" )",
" if script_path:",
].join("\n"),
"v0.20 managed cron missing wake gate"
);
if (patched.includes("workdir=_resolve_job_workdir(job, job_id)")) {
patched = replaceExactlyOnce(
patched,
[
" if script_path:",
" prerun_script = _run_job_script_with_claim_heartbeat(",
" job,",
" script_path,",
" workdir=_resolve_job_workdir(job, job_id),",
" cancel_event=cancel_event,",
" )",
].join("\n"),
[
" if script_path:",
" try:",
" prerun_script = _run_job_script_with_claim_heartbeat(",
" job,",
" script_path,",
" workdir=_resolve_job_workdir(job, job_id),",
" cancel_event=cancel_event,",
" )",
" except Exception as _managed_launch_exc:",
' if str(job.get("name") or "") in _SELLABLE_MANAGED_CUSTOMER_PROGRAM_JOBS:',
" return _sellable_agent_managed_gate_block(",
' job_id, job_name, f"managed wake gate could not start: {_managed_launch_exc}"',
" )",
" raise",
].join("\n"),
"v0.21.3 managed cron launch failure"
);
} else {
patched = replaceExactlyOnce(
patched,
" if script_path:\n prerun_script = _run_job_script_with_claim_heartbeat(job, script_path, cancel_event=cancel_event)",
[
" if script_path:",
" try:",
" prerun_script = _run_job_script_with_claim_heartbeat(job, script_path, cancel_event=cancel_event)",
" except Exception as _managed_launch_exc:",
' if str(job.get("name") or "") in _SELLABLE_MANAGED_CUSTOMER_PROGRAM_JOBS:',
" return _sellable_agent_managed_gate_block(",
' job_id, job_name, f"managed wake gate could not start: {_managed_launch_exc}"',
" )",
" raise",
].join("\n"),
"v0.21.1 managed cron launch failure"
);
}
patched = replaceExactlyOnce(
patched,
[
" _ran_ok, _script_output = prerun_script",
" if _ran_ok and not _parse_wake_gate(_script_output):",
].join("\n"),
[
" _ran_ok, _script_output = prerun_script",
" _managed_wake, _managed_error = _sellable_agent_validate_managed_wake_gate(",
" job, script_path, prerun_script",
" )",
" if _managed_error:",
" return _sellable_agent_managed_gate_block(job_id, job_name, _managed_error)",
" if _ran_ok and not _parse_wake_gate(_script_output):",
].join("\n"),
"v0.20 managed cron wake gate result"
);
}
return patched;
}
if (
patchKind === "skills-cache-freshness-v020" ||
patchKind === "skills-cache-freshness-v021"
) {
let patched = replaceExactlyOnce(
source,
" sig.append((str(d), m))",
[
" skill_files = []",
" for root, dirs, files in os.walk(d, followlinks=False):",
" dirs[:] = sorted(",
" name for name in dirs",
" if not os.path.islink(os.path.join(root, name))",
" )",
' if "SKILL.md" not in files:',
" continue",
' skill_path = os.path.join(root, "SKILL.md")',
" try:",
" skill_stat = os.stat(skill_path, follow_symlinks=False)",
" skill_files.append(",
" (skill_path, skill_stat.st_mtime_ns, skill_stat.st_size)",
" )",
" except OSError:",
" continue",
" sig.append((str(d), m, tuple(skill_files)))",
].join("\n"),
"v0.20 live SKILL.md signature"
);
patched = replaceExactlyOnce(
patched,
" disabled = set() if skip_disabled else _get_disabled_skill_names()",
[
" disabled = _get_disabled_skill_names()",
" filtered_disabled = set() if skip_disabled else disabled",
].join("\n"),
"v0.20 shared disabled signature"
);
patched = replaceExactlyOnce(
patched,
patchKind === "skills-cache-freshness-v021"
? " if name in seen_names or name in disabled:\n continue"
: " if name in disabled:\n continue",
patchKind === "skills-cache-freshness-v021"
? " if name in seen_names or name in filtered_disabled:\n continue"
: " if name in filtered_disabled:\n continue",
"v0.20 filtered disabled behavior"
);
patched = replaceExactlyOnce(
patched,
" skills = []\n seen_names: set = set()",
[
" # A signature change invalidates both filtered and unfiltered",
" # variants together; neither waits for the 30-second TTL.",
" if cached is not None and cached[0] != signature:",
" _SKILLS_CACHE.clear()",
"",
" skills = []",
" seen_names: set = set()",
].join("\n"),
"v0.20 both-variant cache invalidation"
);
return patched;
}
if (
patchKind === "skills-prompt-freshness-v020" ||
patchKind === "skills-prompt-freshness-v021" ||
patchKind === "skills-prompt-freshness-v0215"
) {
let patched = replaceExactlyOnce(
source,
"_SKILLS_PROMPT_CACHE_LOCK = threading.Lock()",
[
"_SKILLS_PROMPT_CACHE_LOCK = threading.Lock()",
"_SELLABLE_AGENT_SKILLS_PROMPT_SIGNATURE = None",
].join("\n"),
"v0.20 prompt signature state"
);
const hasProjectSkillDirs = patched.includes(
" project_dirs = project_dirs or []\n cache_key = ("
);
const cacheKeyAnchor = hasProjectSkillDirs
? [
" disabled = get_disabled_skill_names(_platform_hint or None)",
" project_dirs = project_dirs or []",
" cache_key = (",
].join("\n")
: " disabled = get_disabled_skill_names(_platform_hint or None)\n cache_key = (";
patched = replaceExactlyOnce(
patched,
cacheKeyAnchor,
[
" disabled = get_disabled_skill_names(_platform_hint or None)",
...(hasProjectSkillDirs
? [" project_dirs = project_dirs or []"]
: []),
` signature_roots = [skills_dir, *external_dirs${
hasProjectSkillDirs ? ", *project_dirs" : ""
}]`,
" live_signature = tuple(",
" (",
" str(root),",
" tuple(",
" (path, tuple(values))",
" for path, values in sorted(_build_skills_manifest(root).items())",
" ),",
" )",
" for root in signature_roots",
" if root.exists()",
" )",
" cache_key = (",
].join("\n"),
"v0.20 prompt live signature"
);
if (patchKind === "skills-prompt-freshness-v0215") {
patched = replaceExactlyOnce(
patched,
" _oneshot_prompt_variant(),\n )\n snapshot = _load_skills_snapshot(skills_dir)",
" _oneshot_prompt_variant(),\n live_signature,\n )\n snapshot = _load_skills_snapshot(skills_dir)",
"v0.21.5 prompt signature cache key"
);
// Keep upstream oneshot partitions and app-gated cache bypass intact.
return replaceExactlyOnce(
patched,
" with _SKILLS_PROMPT_CACHE_LOCK:\n cached = _SKILLS_PROMPT_CACHE.get(cache_key)",
[
" global _SELLABLE_AGENT_SKILLS_PROMPT_SIGNATURE",
" with _SKILLS_PROMPT_CACHE_LOCK:",
" if _SELLABLE_AGENT_SKILLS_PROMPT_SIGNATURE != live_signature:",
" _SKILLS_PROMPT_CACHE.clear()",
" _SELLABLE_AGENT_SKILLS_PROMPT_SIGNATURE = live_signature",
" cached = _SKILLS_PROMPT_CACHE.get(cache_key)",
].join("\n"),
"v0.21.5 prompt cache invalidation"
);
}
patched = replaceExactlyOnce(
patched,
(patchKind === "skills-prompt-freshness-v021"
? " _platform_hint, tuple(sorted(disabled)), tuple(sorted(compact_categories or ())),"
: " tuple(sorted(compact_categories or ())),") +
"\n )\n with _SKILLS_PROMPT_CACHE_LOCK:\n cached = _SKILLS_PROMPT_CACHE.get(cache_key)",
[
patchKind === "skills-prompt-freshness-v021"
? " _platform_hint, tuple(sorted(disabled)), tuple(sorted(compact_categories or ())),"
: " tuple(sorted(compact_categories or ())),",
" live_signature,",
" )",
" global _SELLABLE_AGENT_SKILLS_PROMPT_SIGNATURE",
" with _SKILLS_PROMPT_CACHE_LOCK:",
" if _SELLABLE_AGENT_SKILLS_PROMPT_SIGNATURE != live_signature:",
" _SKILLS_PROMPT_CACHE.clear()",
" _SELLABLE_AGENT_SKILLS_PROMPT_SIGNATURE = live_signature",
" cached = _SKILLS_PROMPT_CACHE.get(cache_key)",
].join("\n"),
"v0.20 prompt cache invalidation"
);
return patched;
}
throw new HermesAgentBridgeError(
"HERMES_BRIDGE_UNKNOWN_PATCH_KIND",
`Unknown Hermes bridge patch kind: ${patchKind}`,
{ patchKind }
);
}
function normalizeContract(input) {
if (!input || typeof input !== "object") {
throw new HermesAgentBridgeError(
"HERMES_BRIDGE_INVALID_CONTRACT",
"Bridge contract is required"
);
}
const versionFile = input.versionFile;
if (
!input.hermesVersion ||
!versionFile ||
typeof versionFile.path !== "string" ||
!isSha256(versionFile.sha256) ||
!Array.isArray(input.files) ||
input.files.length === 0
) {
throw new HermesAgentBridgeError(
"HERMES_BRIDGE_INVALID_CONTRACT",
"Bridge contract is malformed"
);
}
const seen = new Set([versionFile.path]);
const files = input.files.map((file) => {
if (
!file ||
typeof file.path !== "string" ||
typeof file.patchKind !== "string" ||
!isSha256(file.sourceSha256) ||
!isSha256(file.patchedSha256) ||
seen.has(file.path)
) {
throw new HermesAgentBridgeError(
"HERMES_BRIDGE_INVALID_CONTRACT",
"Bridge file contract is malformed"
);
}
seen.add(file.path);
return Object.freeze({ ...file });
});
const normalized = {
bridgeId: HERMES_AGENT_BRIDGE_ID,
hermesVersion: String(input.hermesVersion),
versionFile: Object.freeze({ ...versionFile }),
files: Object.freeze(files),
};
return Object.freeze({
...normalized,
contractDigest: sha256(JSON.stringify(normalized)),
});
}
export function createHermesBridgeContractFromSources({
hermesVersion,
versionFilePath = "hermes_cli/__init__.py",
versionFileSource,
files,
}) {
if (typeof versionFileSource !== "string" || !Array.isArray(files)) {
throw new HermesAgentBridgeError(
"HERMES_BRIDGE_INVALID_CONTRACT",
"Source-backed contract is malformed"
);
}
return normalizeContract({
hermesVersion,
versionFile: { path: versionFilePath, sha256: sha256(versionFileSource) },
files: files.map((file) => ({
path: file.path,
patchKind: file.patchKind,
sourceSha256: sha256(file.source),
patchedSha256: sha256(patchHermesSourceFile(file.patchKind, file.source)),
})),
});
}
export const HERMES_AGENT_BRIDGE_CONTRACT = normalizeContract({
hermesVersion: "0.18.0",
versionFile: {
path: "hermes_cli/__init__.py",
sha256: "58b0e216b05a3db1ec84e6eff8087a611261b78f0d3004c31cd83d93c257bbc3",
},
files: [
{
path: "gateway/config.py",
patchKind: "gateway-config",
sourceSha256:
"a08cf991bc6614539389936573b0d179fbe8169db05037df496123308f651b50",
patchedSha256:
"6c629d4a95597c97e115a9d92f85d6f4da6312be7e5ffec81a110d0651961586",
},
{
path: "plugins/platforms/slack/adapter.py",
patchKind: "slack-adapter",
sourceSha256:
"20b12d9bbff0f5b280e0be8e795c7327f4089c3fa8b04d7a6d346dabae591f2a",
patchedSha256:
"548ab70f515e22830cbcbf6b0691768272dd708fd0118f7c601e1e1232bb016b",
},
{
path: "tools/mcp_tool.py",
patchKind: "mcp-tool",
sourceSha256:
"1bcceccaeb8ec8894c83819d389a64258517f4b48db1c8fea5c486633e56fe8b",
patchedSha256:
"651b6e036c95e0b88b9e3bb8d9c636aaea9bf37a91192083dc0b1ffb91842c47",
},
],
});
export const HERMES_AGENT_BRIDGE_V019_CONTRACT = normalizeContract({
hermesVersion: "0.19.0",
versionFile: {
path: "hermes_cli/__init__.py",
sha256: "d9805993b3f400e9891c9dc97acb2ff1554f54c78061d57dc48a80493e244157",
},
files: [
{
path: "gateway/config.py",
patchKind: "gateway-config-v019",
sourceSha256:
"7221ee05798566ca7cf570035615a9b29034cf92ce5a6eaa5eec0693040c08aa",
patchedSha256:
"764ffffdb6fb5d612b6ac226aadcf10030c24d259bd741cb98b77d18d823e580",
},
{
path: "gateway/profile_routing.py",
patchKind: "profile-routing-v019",
sourceSha256:
"1948c862fe2cdd3b9dd211e8bff7be1269a3b413e6c370192dac7e1f47f44c44",
patchedSha256:
"9dcedc1a895a2a031bc117db68c2ebba5659aadada2e15294f502bbe39147fa7",
},
{
path: "plugins/platforms/slack/adapter.py",
patchKind: "slack-adapter-v019",
sourceSha256:
"b89cb173a98c4ec948198556da9f8dfce66d3b44754a0a24a38f9c5f30add817",
patchedSha256:
"3a2d59ab3f7637d1fca668a513db71e5d8b557e7eb44cf3c1ab3d56480461867",
},
{
path: "tools/mcp_tool.py",
patchKind: "mcp-tool",
sourceSha256:
"a7328f3f3762ae43f6a9426646b0c28c17ec8663aa391506f48d628035ad5460",
patchedSha256:
"1ed7388ca812d6676007b332120ad45bc949fdbdce8eeada88f433bec5f94673",
},
],
});
export const HERMES_AGENT_BRIDGE_CONTRACT_V019 =
HERMES_AGENT_BRIDGE_V019_CONTRACT;
export const HERMES_AGENT_BRIDGE_DEDICATED_V019_CONTRACT = normalizeContract({
hermesVersion: "0.19.1",
versionFile: {
path: "hermes_cli/__init__.py",
sha256: "653172511583adb549dc18fa71d6dde11dcbf2b85db8513ce896f8631e94fffd",
},
files: [
{
path: "gateway/config.py",
patchKind: "gateway-config-dedicated-v019",
sourceSha256:
"c5138c0dce57ee148399b01fc4ec56f6cf1d8d0229b16c338b01254b59816e7f",
patchedSha256:
"6970e3fec4c0fbe3357f8f8e03950f129e3f1c98178308bfb7f2ab99dfbc020e",
},
{
path: "plugins/platforms/slack/adapter.py",
patchKind: "slack-adapter-dedicated-v019",
sourceSha256:
"a58a82ce2af5137bf2452c89a5aaed6d6af562eef6fdad5597be17e15a4227ce",
patchedSha256:
"5b43bcb637f6cd602b2bd8642310091b4633b0934d14149d87665a91b512bba8",
},
{
path: "tools/mcp_tool.py",
patchKind: "mcp-tool",
sourceSha256:
"562e48fa192562000c852103c4f9f2e939dd41398605731b709389e03fd4f22d",
patchedSha256:
"8ed9c8bde6f35a5f159a218840a37054531269141d0ab8dfcb789de1fa0799bb",
},
],
});
export const HERMES_AGENT_BRIDGE_DEDICATED_V020_CONTRACT = normalizeContract({
hermesVersion: "0.20.4",
versionFile: {
path: "hermes_cli/__init__.py",
sha256: "ac4b7eb9d0d62a050e936d8d09168efe0cc72ccd3056a4d9340069f5c39a1305",
},
files: [
{
path: "gateway/config.py",
patchKind: "gateway-config-dedicated-v019",
sourceSha256:
"abb44862cc7f5b503d5c087c99dc7f923e325ccf7cf1d5e3540bf1c40837536a",
patchedSha256:
"2718cb4a45057b6f84623437d62f18e00197c389071394b7607fe7f8e6bf0ca2",
},
{
path: "plugins/platforms/slack/adapter.py",
patchKind: "slack-adapter-dedicated-v019",
sourceSha256:
"d3db079d731adf1fd3e41682376651a0ad833526cca4bf45c0b56cd1657c51a7",
patchedSha256:
"3c7b560d6c27e0ad151c4310b0559dd8685f6ac3a6bfc994f82d4fff4766727f",
},
{
path: "tools/mcp_tool.py",
patchKind: "mcp-tool-endpoint-v020",
sourceSha256:
"8ce75e7f2d999edf6554a8f5a037289c885bc9427263da1cd6e3448e608fe20f",
patchedSha256:
"e4bf77633c8333d1f79310768c0824e8eaed87938ec7ffd2478050f12f5d36a6",
},
{
path: "gateway/run.py",
patchKind: "gateway-session-v020",
sourceSha256:
"97a3173d1a7ee0df98822d3ba173c72e997e52460bf64193b6f2c68ab20a48e3",
patchedSha256:
"af08998cb177636bc575ef524d94318911a99870b39bf293e3fa1adfaba96120",
},
{
path: "agent/turn_context.py",
patchKind: "turn-context-v020",
sourceSha256:
"4a65e543a0795c341fd7598ac42a40eb2d87da6637a3521ecc3a00096eb56896",
patchedSha256:
"f4768b3992a1a64832b82ac66981a014c1ef53bfd3f336f3d1890e348a107d7f",
},
{
path: "cron/scheduler.py",
patchKind: "cron-scheduler-v020",
sourceSha256:
"ac0d2f0edcfaf26ffa21aa4e7478b44bb78e6f43e3072697e2849f2b1b13b7e7",
patchedSha256:
"c0d3e30b9eeca1871b7133924ec0621d7a5265536379c26561e6e3062bd7c1cf",
},
{
path: "tools/skills_tool.py",
patchKind: "skills-cache-freshness-v020",
sourceSha256:
"c601bc4ed4dac3fbea22666239d6aa3085bbe2f4a4c0d2db1ab3d2eb5d947de9",
patchedSha256:
"af89fb92a4b0c8032328e7f26c70925e581e3d1208d24fedf5b0df2df4b5c209",
},
{
path: "agent/prompt_builder.py",
patchKind: "skills-prompt-freshness-v020",
sourceSha256:
"bfb9a774d0c6c2490bc26fcef727ed2d38d0be2fab62a4782f69230101c9e997",
patchedSha256:
"30d7d9a45e3cce31ed5805bb048914dec577e743d6e21be573dec0cfa579d0b7",
},
],
});
export const HERMES_AGENT_BRIDGE_DEDICATED_V021_CONTRACT = normalizeContract({
bridgeId: "sellable-agent-hermes-bridge/v1",
hermesVersion: "0.21.1",
versionFile: {
path: "hermes_cli/__init__.py",
sha256: "efae023ac37622277aac298ac15c646b855e870132c38970feeda9552f1ecc27",
},
files: [
{
path: "gateway/platforms/api_server.py",
patchKind: "api-opener-stage-v021",
sourceSha256:
"221589ae8c45349736bb291b4679b86e9e12cb22f5a33220ae3d22929fea8297",
patchedSha256:
"b029a26050aa777a520ab136c203f3755b178e04af11ca6e9f810046a9eae6d4",
},
{
path: "gateway/config_env.py",
patchKind: "gateway-config-dedicated-v021",
sourceSha256:
"984ae7b68befecd52fc17b6d38e763f40c7040a2ba69ed4a2c39f1a88ae6734a",
patchedSha256:
"0180fbcb1df6e5a7651f172c492a8e317f7455c8ed0e955c7a4f0488fa23b6c2",
},
{
path: "plugins/platforms/slack/adapter.py",
patchKind: "slack-adapter-dedicated-v021",
sourceSha256:
"23048a107304993686250af044256199be2f73171bb5b4cca6a900ea272a6064",
patchedSha256:
"bc05fd5f227e42f733ee78c80ffab6c7c53840975fc5bc9755aa2ef8f2c8ff47",
},
{
path: "tools/mcp_tool_handlers.py",
patchKind: "mcp-tool-endpoint-v021",
sourceSha256:
"e6af250f0fbfeb12a936c340a46f40f8d40332ed8bbc4eb63fded66e37aaa7bf",
patchedSha256:
"6c4765aad3074b6f8ad6951299edafa36cf536c9a9f0b57a48bdd541e3209790",
},
{
path: "gateway/run.py",
patchKind: "gateway-session-v021",
sourceSha256:
"3b1f670243d4932ac1f2a2a68bee61a8c7f9bcdac7bd48d43289db90f17bab67",
patchedSha256:
"2e25d50add6c49748b2cdd4c2bd115039e72c0b4eeb9c882eb1cd07a2a25c304",
},
{
path: "gateway/run_turn_runner.py",
patchKind: "gateway-provider-preflight-v021",
sourceSha256:
"8ebd74318db2259ac52c35dbf9568b98dbb19c1d2e30289f4efc76a12ac8ceeb",
patchedSha256:
"26a13f167835036c37ff92da3c1d036267544cf8a6529f5d40c3ee0ae58fa1cb",
},
{
path: "agent/turn_context.py",
patchKind: "turn-context-v021",
sourceSha256:
"d1a84a24c5b50a7a866268fde453694c6b98790e31d7d4310d8756027149863a",
patchedSha256:
"13517e034866224c072a860dbd9fbb7eb25c9d3cb86a1f59ae3a2e5ec1cef7ad",
},
{
path: "cron/scheduler.py",
patchKind: "cron-scheduler-v020",
sourceSha256:
"f1891e94697ccf5f7b66ae7788345368b452af447fbc43356ae5376a3c753518",
patchedSha256:
"03d0848e584b7cbc5b126e0fae989dbd5d3d83ccee3ad989c08ffc8f8ef423b9",
},
{
path: "tools/skills_tool.py",
patchKind: "skills-cache-freshness-v021",
sourceSha256:
"0f205b8c2d9266d272d8c6cae3d189b86a5aebce98f03b61605d266b65f9497c",
patchedSha256:
"8696b37ef58c0cc570c437abac730ac0e670e44365ddeae452ad40a501f13a1b",
},
{
path: "agent/prompt_builder.py",
patchKind: "skills-prompt-freshness-v021",
sourceSha256:
"83160fab72772012bc308bc730a0085e7acb126f1bea49d62f990505f00ce677",
patchedSha256:
"6ab2aa30e06b124333d28ed73fc7b56394fbc71f040f3387f6fbc835d799f266",
},
],
contractDigest:
"a8520b6decd64b43de1074005c8eda2d9be4a451f0f9a43b1777659acd5a86b6",
});
export const HERMES_AGENT_BRIDGE_DEDICATED_V0213_CONTRACT = normalizeContract({
bridgeId: "sellable-agent-hermes-bridge/v1",
hermesVersion: "0.21.3",
versionFile: {
path: "hermes_cli/__init__.py",
sha256: "0d78a58a9f27f32adfdac959e89767cecde93a424bcfbd39d64fb95f6cf13e6c",
},
files: [
{
path: "gateway/config_env.py",
patchKind: "gateway-config-dedicated-v021",
sourceSha256:
"40bb1029e482ebe423a5a6ddc9175ef96f821f89e9e040b5cf62cdd7ec903e4c",
patchedSha256:
"c189faaa2ab7c0ea603b44eb3e6b37dcf847a83b12f603ca185f37ba0ca582fc",
},
{
path: "plugins/platforms/slack/adapter.py",
patchKind: "slack-adapter-dedicated-v0213",
sourceSha256:
"12bb80dffde14eca299f6f0fa57907fbe1636519402c08dc07d96d1c144e5f83",
patchedSha256:
"da13c90b8a81c32b57909e5d82f9e3500d14b290cf9a38ffd6dd53e77785e038",
},
{
path: "tools/mcp_tool_handlers.py",
patchKind: "mcp-tool-endpoint-v021",
sourceSha256:
"c4713aa289c7ca17b53c0ae53ceb6a276321f6d36e259084974e8b5738b6a4dd",
patchedSha256:
"1bd801ebf1c6e17a0d81899b2ee0401f038ae4d1a493552f021a1b66fccf0e98",
},
{
path: "gateway/run.py",
patchKind: "gateway-session-v021",
sourceSha256:
"ab619aa0dc193c6d8741f3cabc9a028c2fb7459c22262c69597b0e872091bde5",
patchedSha256:
"50fc00c3fa236c201d4f4e0831ec728d87ee7ad16b0865c69242304a5de65a23",
},
{
path: "gateway/run_turn.py",
patchKind: "gateway-first-contact-v0213",
sourceSha256:
"56e6fb62b60e954ef0d258c7c44ed3fca99c4aa6d2c502d8f80a1c516569f537",
patchedSha256:
"d66e2aecd00ebb1c6f30a1ecc522b1f408d4a8ff1413b63516752e17ea0e55a1",
},
{
path: "gateway/run_turn_runner.py",
patchKind: "gateway-provider-preflight-v021",
sourceSha256:
"b87d6072f2cc13634398d380eb0857d550f75502a8ace137138cf16e00d9a763",
patchedSha256:
"0113b3df868e73c7f06bacf0c5cec916077e21973e3c1b03b6778c3b91e92b8b",
},
{
path: "agent/turn_context.py",
patchKind: "turn-context-v021",
sourceSha256:
"46ed030ee35a13f75994bf8e28cde3633db14969d1fb5c859fc0ff6964cbb0bd",
patchedSha256:
"facc6ff45a479766b0c0fe719d96fd6867ee25c40e638d5e82499cc97bd72e04",
},
{
path: "cron/scheduler.py",
patchKind: "cron-scheduler-v020",
sourceSha256:
"df7b82c50485cece408264f3cd44dc910b6b2a7d319b6d138bd42e2cf7ba2e86",
patchedSha256:
"ea8b4df9d12dbd82c59044d401de5e99ed466657ac873f018ac5d8d741893b2c",
},
{
path: "tools/skills_tool.py",
patchKind: "skills-cache-freshness-v021",
sourceSha256:
"1bec6a244ac61603b1adeb5599149a4097b68263458f63eafe55836415e5f3a0",
patchedSha256:
"168bad88d45af80328c38296be3f1c9b3509f680a7939735836feac94328843e",
},
{
path: "agent/prompt_builder.py",
patchKind: "skills-prompt-freshness-v021",
sourceSha256:
"586ea363fa1e70bb0fdd5426af40758976a16c54f07efeb7a1b4f3fe0ad99309",
patchedSha256:
"769a0662a396bcb0ffb82e14cacd03b2b864526e68c1cde601f68ccea61e2836",
},
{
path: "gateway/platforms/api_server.py",
patchKind: "api-opener-stage-v021",
sourceSha256:
"7ec405dc2a59789582ad9f61a189a41079e621f14642d3c9dc754e312616a868",
patchedSha256:
"1423ea98ec142e9b0dc5ba423dadfe9cf192c39c0565cf58cafc374805725052",
},
],
contractDigest:
"75b5d16081dd2fdc5795d3b86d341f2ff341bf3c599e4c57de5ec14b3dd63ce0",
});
export const HERMES_AGENT_BRIDGE_DEDICATED_V0215_CONTRACT = normalizeContract({
bridgeId: "sellable-agent-hermes-bridge/v1",
hermesVersion: "0.21.5",
versionFile: {
path: "hermes_cli/__init__.py",
sha256: "d05c98cd44e22781497a20cd968af0d9b8962406b909f1889168c624545b229e",
},
files: [
{
path: "gateway/config_env.py",
patchKind: "gateway-config-dedicated-v021",
sourceSha256:
"5661d9cfb7d798d6c995b03727bdd4018669ae12c96d1e7a8f3c99a3ea85acc7",
patchedSha256:
"cd8efa414e0313bca77d0d8093acc505d9f345b8fb48d734821e66027545bf57",
},
{
path: "plugins/platforms/slack/adapter.py",
patchKind: "slack-adapter-dedicated-v0213",
sourceSha256:
"3f2ec0cef97964bf4cb1e9791c0917a03cd1e73bb0bc3293768680cd6302f613",
patchedSha256:
"26cedfad352e8dadae82bebcedf8813ef948622a350b392ce99097a8ede2f056",
},
{
path: "tools/mcp_tool_handlers.py",
patchKind: "mcp-tool-endpoint-v021",
sourceSha256:
"d1b4463309a2de351aaf6c7cd8f7a2a1e83f5e26dbe058371c9eeb9d0c567903",
patchedSha256:
"61ceab8c24aef50e88d6c1dad1bbf80daed66f8950b05fb642525a62a0bb789c",
},
{
path: "gateway/run.py",
patchKind: "gateway-session-v021",
sourceSha256:
"324f7095223816b865dd68a75dc83bfd1c3d101ac8c1c38dba69026dab2b6af1",
patchedSha256:
"4b398b8c033e5aaba90b6ba312baf01e7d88d46a91843e64949ade0b65f2ade8",
},
{
path: "gateway/run_turn.py",
patchKind: "gateway-first-contact-v0213",
sourceSha256:
"5bdee5c82c00e02f664516f9da0af99674e23493ec2a30eff06cb03afc6718a0",
patchedSha256:
"0729145f27559df970c16d5be11e01ebce657874e4be1d9e151562042f5208c0",
},
{
path: "gateway/run_turn_runner.py",
patchKind: "gateway-provider-preflight-v021",
sourceSha256:
"216bdca083b7d2bfae481d07bd0791a76834674b3614fd4ee0aafac5c58f30db",
patchedSha256:
"7b6beabeed7b78781d142dcdb0eff4c0110263ee173f7696737c4c965e1c72ab",
},
{
path: "agent/turn_context.py",
patchKind: "turn-context-v021",
sourceSha256:
"85f857dc3c317366d918516bc8b37a022f1020b34da0c3966a31bd289b2942e1",
patchedSha256:
"a6487c43bc2d21f40e3a86fe31a9a0c2e4e603fff813f7c8429bbf5c22591648",
},
{
path: "cron/scheduler.py",
patchKind: "cron-scheduler-v020",
sourceSha256:
"dcf0e6794a220e478584a21f786b8451b915fc7397d38eda357af1363249fa2a",
patchedSha256:
"e98d197ce3d0b414184e3c746fe3814c213407da68ce0a46a8b4dd63a9054a11",
},
{
path: "tools/skills_tool.py",
patchKind: "skills-cache-freshness-v021",
sourceSha256:
"0d47bda41ed9d1ec84856df3d336a42bb94161e89bd9a8b857e76ec76be9f7b7",
patchedSha256:
"1bdc17603f3bb9fb34c5d04099dee2ca7d631eedc58b523bcd74d6e946dc9eb7",
},
{
path: "agent/prompt_builder.py",
patchKind: "skills-prompt-freshness-v0215",
sourceSha256:
"64bc77a26641754b8c5ca76fc876687d3c9e81aad7816c2e76ce251a41121526",
patchedSha256:
"56edefd92c50f38a3fed8d56b6fc02352f8e5892b43553ab277e3113606d25fb",
},
{
path: "gateway/platforms/api_server.py",
patchKind: "api-opener-stage-v021",
sourceSha256:
"fa83a20bd4f9f3a90a3ac010db0a68f548259587946ea80b81b2f3253bafd5ec",
patchedSha256:
"dbe6e400c7c7a9d3b377b7f9f08e05f2e9f6b622f9019f873e4fdb0cd828b19f",
},
],
contractDigest:
"d8b2ee47591435091a81a3e9913ba5acace2f9c1418cf75c0e23b4d0632e4024",
});
function assertRelativeContractPath(path) {
if (
!path ||
isAbsolute(path) ||
path.split(/[\\/]+/).some((part) => part === ".." || part === "")
) {
throw new HermesAgentBridgeError(
"HERMES_BRIDGE_UNSAFE_PATH",
"Bridge contract path is unsafe",
{ path }
);
}
}
function resolveConfined(root, path) {
assertRelativeContractPath(path);
const candidate = resolve(root, path);
const rel = relative(root, candidate);
if (!rel || rel === ".." || rel.startsWith(`..${sep}`) || isAbsolute(rel)) {
throw new HermesAgentBridgeError(
"HERMES_BRIDGE_UNSAFE_PATH",
"Bridge path escapes source root",
{ path }
);
}
return candidate;
}
function assertSafeRegularFile(root, path) {
const candidate = resolveConfined(root, path);
let cursor = root;
for (const component of relative(root, candidate).split(sep)) {
cursor = join(cursor, component);
const info = lstatSync(cursor);
if (info.isSymbolicLink()) {
throw new HermesAgentBridgeError(
"HERMES_BRIDGE_SYMLINK",
"Hermes bridge paths may not contain symlinks",
{ path }
);
}
if (
cursor !== candidate &&
(!info.isDirectory() || (info.mode & 0o022) !== 0)
) {
throw new HermesAgentBridgeError(
"HERMES_BRIDGE_UNSAFE_DIRECTORY",
"Hermes bridge parent directories must be real and not group/world writable",
{ path }
);
}
}
const info = lstatSync(candidate);
if (!info.isFile()) {
throw new HermesAgentBridgeError(
"HERMES_BRIDGE_NOT_REGULAR",
"Hermes bridge target is not a regular file",
{ path }
);
}
if ((info.mode & 0o022) !== 0) {
throw new HermesAgentBridgeError(
"HERMES_BRIDGE_WRITABLE_SOURCE",
"Hermes bridge target is group/world writable",
{ path }
);
}
return { candidate, info };
}
function validateSourceRoot(sourceRoot) {
if (
typeof sourceRoot !== "string" ||
!isAbsolute(sourceRoot) ||
resolve(sourceRoot) !== sourceRoot
) {
throw new HermesAgentBridgeError(
"HERMES_BRIDGE_UNSAFE_ROOT",
"Hermes source root must be an absolute normalized path"
);
}
const rootInfo = lstatSync(sourceRoot);
if (
!rootInfo.isDirectory() ||
rootInfo.isSymbolicLink() ||
realpathSync(sourceRoot) !== sourceRoot
) {
throw new HermesAgentBridgeError(
"HERMES_BRIDGE_UNSAFE_ROOT",
"Hermes source root must be a real directory"
);
}
if ((rootInfo.mode & 0o022) !== 0) {
throw new HermesAgentBridgeError(
"HERMES_BRIDGE_WRITABLE_ROOT",
"Hermes source root is group/world writable"
);
}
return sourceRoot;
}
function readVersion(source) {
const match = source.match(/^__version__\s*=\s*["']([^"']+)["']/m);
return match?.[1] ?? null;
}
function publicFileReceipts(files) {
return files.map(({ path, sha256: digest }) => ({ path, sha256: digest }));
}
export function inspectHermesAgentBridge({
sourceRoot,
contract = HERMES_AGENT_BRIDGE_CONTRACT,
}) {
const pinned = normalizeContract(contract);
const root = validateSourceRoot(sourceRoot);
const versionTarget = assertSafeRegularFile(root, pinned.versionFile.path);
const versionBytes = readFileSync(versionTarget.candidate);
const versionSource = versionBytes.toString("utf8");
const versionDigest = sha256(versionBytes);
const version = readVersion(versionSource);
const reasons = [];
if (versionDigest !== pinned.versionFile.sha256)
reasons.push("VERSION_FILE_HASH_MISMATCH");
if (version !== pinned.hermesVersion) reasons.push("HERMES_VERSION_MISMATCH");
const files = pinned.files.map((file) => {
const target = assertSafeRegularFile(root, file.path);
const digest = sha256(readFileSync(target.candidate));
const state =
digest === file.sourceSha256
? "source"
: digest === file.patchedSha256
? "patched"
: "unknown";
if (state === "unknown") reasons.push(`UNKNOWN_SOURCE:${file.path}`);
return {
...file,
absolutePath: target.candidate,
mode: target.info.mode & 0o777,
sha256: digest,
state,
};
});
const knownStates = new Set(files.map((file) => file.state));
if (knownStates.has("source") && knownStates.has("patched"))
reasons.push("MIXED_BRIDGE_STATE");
let state = "blocked";
if (
reasons.length === 0 &&
knownStates.size === 1 &&
knownStates.has("source")
)
state = "needs_install";
if (
reasons.length === 0 &&
knownStates.size === 1 &&
knownStates.has("patched")
)
state = "installed";
return Object.freeze({
bridgeId: pinned.bridgeId,
contractDigest: pinned.contractDigest,
hermesVersion: version,
state,
reasons: Object.freeze(reasons),
files: Object.freeze(publicFileReceipts(files)),
});
}
function fsyncDirectory(path) {
const fd = openSync(path, constants.O_RDONLY);
try {
fsyncSync(fd);
} finally {
closeSync(fd);
}
}
function atomicReplace(candidate, bytes, { mode, uid, gid }) {
const temp = join(
dirname(candidate),
`.${candidate.split(sep).at(-1)}.sellable-agent-${process.pid}-${Date.now()}.tmp`
);
let fd;
try {
fd = openSync(
temp,
constants.O_CREAT |
constants.O_EXCL |
constants.O_WRONLY |
constants.O_NOFOLLOW,
mode
);
writeFileSync(fd, bytes);
fchmodSync(fd, mode);
fchownSync(fd, uid, gid);
fsyncSync(fd);
closeSync(fd);
fd = undefined;
renameSync(temp, candidate);
fsyncDirectory(dirname(candidate));
} finally {
if (fd !== undefined) closeSync(fd);
if (existsSync(temp)) unlinkSync(temp);
}
}
export function installHermesAgentBridge({
sourceRoot,
contract = HERMES_AGENT_BRIDGE_CONTRACT,
}) {
const pinned = normalizeContract(contract);
const before = inspectHermesAgentBridge({ sourceRoot, contract: pinned });
if (before.state === "installed")
return Object.freeze({ ...before, status: "already_current" });
if (before.state !== "needs_install") {
throw new HermesAgentBridgeError(
"HERMES_BRIDGE_SOURCE_REJECTED",
"Hermes source does not match the pinned bridge preimage",
{ state: before.state, reasons: before.reasons }
);
}
const staged = pinned.files.map((file) => {
const { candidate, info } = assertSafeRegularFile(sourceRoot, file.path);
const original = readFileSync(candidate);
const patched = Buffer.from(
patchHermesSourceFile(file.patchKind, original.toString("utf8")),
"utf8"
);
const digest = sha256(patched);
if (digest !== file.patchedSha256) {
throw new HermesAgentBridgeError(
"HERMES_BRIDGE_PATCH_DIGEST_MISMATCH",
"Generated Hermes patch does not match the pinned postimage",
{ path: file.path }
);
}
return {
...file,
candidate,
ownership: { mode: info.mode & 0o777, uid: info.uid, gid: info.gid },
original,
patched,
};
});
const replaced = [];
try {
for (const file of staged) {
atomicReplace(file.candidate, file.patched, file.ownership);
replaced.push(file);
}
} catch (error) {
const rollbackErrors = [];
for (const file of replaced.reverse()) {
try {
atomicReplace(file.candidate, file.original, file.ownership);
} catch (rollbackError) {
rollbackErrors.push({
path: file.path,
message:
rollbackError instanceof Error
? rollbackError.message
: String(rollbackError),
});
}
}
throw new HermesAgentBridgeError(
rollbackErrors.length
? "HERMES_BRIDGE_ROLLBACK_FAILED"
: "HERMES_BRIDGE_INSTALL_FAILED",
rollbackErrors.length
? "Hermes bridge install and rollback failed"
: "Hermes bridge install failed and was rolled back",
{
rollbackErrors,
cause: error instanceof Error ? error.message : String(error),
}
);
}
const after = inspectHermesAgentBridge({ sourceRoot, contract: pinned });
if (after.state !== "installed") {
throw new HermesAgentBridgeError(
"HERMES_BRIDGE_VERIFY_FAILED",
"Hermes bridge post-install verification failed",
{
state: after.state,
reasons: after.reasons,
}
);
}
return Object.freeze({ ...after, status: "installed" });
}
export function verifyHermesAgentBridge({
sourceRoot,
contract = HERMES_AGENT_BRIDGE_CONTRACT,
}) {
const observation = inspectHermesAgentBridge({ sourceRoot, contract });
if (observation.state !== "installed") {
throw new HermesAgentBridgeError(
"HERMES_BRIDGE_NOT_INSTALLED",
"Pinned Hermes bridge is not installed",
{
state: observation.state,
reasons: observation.reasons,
}
);
}
return Object.freeze({ ...observation, status: "verified" });
}