@sellable/install 0.1.766 → 0.1.768-wip.hermes-20260925.4
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/container/Dockerfile +4 -4
- package/container/README.md +1 -1
- package/lib/sellable-agent/fly-admin-image/Dockerfile +4 -4
- package/lib/sellable-agent/fly-admin-image/admin-runtime.mjs +10 -7
- package/lib/sellable-agent/fly-customer-image/Dockerfile +6 -6
- package/lib/sellable-agent/fly-customer-image/customer-runtime.mjs +11 -4
- package/lib/sellable-agent/fly-customer-image/hermes-runs-client.mjs +5 -5
- package/lib/sellable-agent/fly-customer-worker.mjs +6 -0
- package/lib/sellable-agent/fly-runtime-identity.mjs +1 -1
- package/lib/sellable-agent/hermes-bridge.mjs +109 -9
- package/lib/sellable-agent/hermes-memory-snapshot.mjs +1 -1
- package/lib/sellable-agent/host-bootstrap.mjs +1 -1
- package/lib/sellable-agent/host-worker.mjs +1 -1
- package/lib/sellable-agent/model-auth-reconciler.mjs +13 -7
- package/lib/sellable-agent/profile-materializer.mjs +2 -2
- package/lib/sellable-agent/provisioning-adapter.mjs +1 -1
- package/package.json +1 -1
package/container/Dockerfile
CHANGED
|
@@ -3,12 +3,12 @@ FROM ${HERMES_IMAGE}
|
|
|
3
3
|
|
|
4
4
|
USER root
|
|
5
5
|
|
|
6
|
-
ARG INSTALLER_PACKAGE=@sellable/install@0.1.
|
|
6
|
+
ARG INSTALLER_PACKAGE=@sellable/install@0.1.768-wip.hermes-20260925.4
|
|
7
7
|
ARG MCP_PACKAGE=@sellable/mcp@0.1.941
|
|
8
8
|
ARG INSTALLER_INTEGRITY
|
|
9
9
|
ARG MCP_INTEGRITY=sha512-Dhi+r50kwZa0E6iskB7dmDM/kCe9woEExLXxfLg8jf9LSKj86V5AiC0jhpS7euoo/lvY5e9m2a0BlTV9wqFxRQ==
|
|
10
10
|
|
|
11
|
-
RUN test "${INSTALLER_PACKAGE}" = "@sellable/install@0.1.
|
|
11
|
+
RUN test "${INSTALLER_PACKAGE}" = "@sellable/install@0.1.768-wip.hermes-20260925.4" \
|
|
12
12
|
&& test "${MCP_PACKAGE}" = "@sellable/mcp@0.1.941" \
|
|
13
13
|
&& test -n "${INSTALLER_INTEGRITY}" \
|
|
14
14
|
&& test "$(npm view "${INSTALLER_PACKAGE}" dist.integrity)" = "${INSTALLER_INTEGRITY}" \
|
|
@@ -23,9 +23,9 @@ RUN test "${INSTALLER_PACKAGE}" = "@sellable/install@0.1.766" \
|
|
|
23
23
|
&& mkdir -p /opt/sellable-agent/install-root /opt/sellable-agent/mcp-root \
|
|
24
24
|
&& npm install --prefix /opt/sellable-agent/install-root --omit=dev --ignore-scripts --no-audit --no-fund "${INSTALLER_PACKAGE}" \
|
|
25
25
|
&& npm install --prefix /opt/sellable-agent/mcp-root --omit=dev --ignore-scripts --no-audit --no-fund "${MCP_PACKAGE}" \
|
|
26
|
-
&& node --input-type=module -e "import { readFileSync } from 'node:fs'; const install = JSON.parse(readFileSync('/opt/sellable-agent/install-root/node_modules/@sellable/install/package.json')); const mcp = JSON.parse(readFileSync('/opt/sellable-agent/mcp-root/node_modules/@sellable/mcp/package.json')); if (install.name !== '@sellable/install' || install.version !== '0.1.
|
|
26
|
+
&& node --input-type=module -e "import { readFileSync } from 'node:fs'; const install = JSON.parse(readFileSync('/opt/sellable-agent/install-root/node_modules/@sellable/install/package.json')); const mcp = JSON.parse(readFileSync('/opt/sellable-agent/mcp-root/node_modules/@sellable/mcp/package.json')); if (install.name !== '@sellable/install' || install.version !== '0.1.768-wip.hermes-20260925.4' || mcp.name !== '@sellable/mcp' || mcp.version !== '0.1.941') throw new Error('package identity rejected');" \
|
|
27
27
|
&& node --input-type=module -e "import { buildExternalRuntimeClosure } from '/opt/sellable-agent/install-root/node_modules/@sellable/install/lib/sellable-agent/external-runtime-builder.mjs'; const built = buildExternalRuntimeClosure({ mcpPackageRoot: '/opt/sellable-agent/mcp-root/node_modules/@sellable/mcp', mcpNodeModulesRoot: '/opt/sellable-agent/mcp-root/node_modules', hermesSourceRoot: '/opt/hermes', ownerUid: 0, ownerGid: 0 }); if (!built.closureDigest) throw new Error('runtime closure rejected');" \
|
|
28
|
-
&& node --input-type=module -e "import { chmodSync, writeFileSync } from 'node:fs'; const release = { installerPackage: '@sellable/install@0.1.
|
|
28
|
+
&& node --input-type=module -e "import { chmodSync, writeFileSync } from 'node:fs'; const release = { installerPackage: '@sellable/install@0.1.768-wip.hermes-20260925.4', installerIntegrity: process.argv[1], mcpPackage: '@sellable/mcp@0.1.941', mcpIntegrity: process.argv[2] }; writeFileSync('/opt/sellable-agent/release.json', JSON.stringify(release) + '\\n', { mode: 0o444 }); chmodSync('/opt/sellable-agent/release.json', 0o444);" "${INSTALLER_INTEGRITY}" "${MCP_INTEGRITY}" \
|
|
29
29
|
&& npm cache clean --force
|
|
30
30
|
|
|
31
31
|
COPY entrypoint.sh /usr/local/bin/sellable-agent-container-entrypoint
|
package/container/README.md
CHANGED
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
This image is a dedicated Agent worker/runtime boundary beside an existing Hermes dashboard. It never replaces or reconfigures the dashboard container.
|
|
4
4
|
|
|
5
5
|
Build from this directory after
|
|
6
|
-
`@sellable/install@0.1.
|
|
6
|
+
`@sellable/install@0.1.768-wip.hermes-20260925.4` is
|
|
7
7
|
published:
|
|
8
8
|
|
|
9
9
|
```sh
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
# syntax=docker/dockerfile:1.7
|
|
2
|
-
ARG HERMES_IMAGE=nousresearch/hermes-agent@sha256:
|
|
2
|
+
ARG HERMES_IMAGE=nousresearch/hermes-agent@sha256:fca358f12efd65bfaaca05884166f15c0e2788375ca30d77061ac1ebc96452b7
|
|
3
3
|
ARG SLACK_PP_GO_IMAGE=golang@sha256:386d475a660466863d9f8c766fec64d7fdad3edac2c6a05020c09534d71edb4b
|
|
4
4
|
|
|
5
5
|
FROM ${SLACK_PP_GO_IMAGE} AS slack-pp-cli-builder
|
|
@@ -37,8 +37,8 @@ ARG MCP_TRUST_ROOT_FINGERPRINT
|
|
|
37
37
|
ARG TUS_JS_CLIENT_VERSION=4.3.1
|
|
38
38
|
ARG YAML_VERSION=2.9.0
|
|
39
39
|
ARG AGENT_BROWSER_VERSION=0.26.0
|
|
40
|
-
ARG PLAYWRIGHT_VERSION=1.
|
|
41
|
-
ARG PLAYWRIGHT_BROWSER_REVISION=
|
|
40
|
+
ARG PLAYWRIGHT_VERSION=1.63.0
|
|
41
|
+
ARG PLAYWRIGHT_BROWSER_REVISION=1243
|
|
42
42
|
ARG STRIPE_CLI_PACKAGE=@stripe/cli-linux-x64@1.45.0
|
|
43
43
|
ARG STRIPE_CLI_INTEGRITY=sha512-1ZhoPpoweYfynqsvhCLlTjZ7lPz5IKtxqAMT5MBy6zrwLRTP9x0T6r8h/jLYL8lRH1c7zC/6X6/XUu2V+r9Bog==
|
|
44
44
|
ARG DEFAULT_PROFILE_BUNDLE_FIXTURE_VERSION=1
|
|
@@ -217,7 +217,7 @@ RUN set -eux; \
|
|
|
217
217
|
'const fs=require("fs"); const manifest=JSON.parse(fs.readFileSync("/usr/local/share/sellable-agent/default-profile-bundle/manifest.json")); if(String(manifest.bundleVersion)!==process.argv[1] || manifest.bundleDigest!==process.argv[2]) process.exit(1);' \
|
|
218
218
|
"${DEFAULT_PROFILE_BUNDLE_VERSION}" "${DEFAULT_PROFILE_BUNDLE_DIGEST}" \
|
|
219
219
|
&& node --input-type=module -e \
|
|
220
|
-
'import { installHermesAgentBridge,
|
|
220
|
+
'import { installHermesAgentBridge, HERMES_AGENT_BRIDGE_DEDICATED_V0215_CONTRACT } from "/usr/local/lib/sellable-agent/hermes-bridge.mjs"; installHermesAgentBridge({ sourceRoot: "/opt/hermes", contract: HERMES_AGENT_BRIDGE_DEDICATED_V0215_CONTRACT });' \
|
|
221
221
|
&& node --input-type=module -e \
|
|
222
222
|
'await import("/usr/local/lib/sellable-agent/fly-runtime-identity.mjs");' \
|
|
223
223
|
&& node --input-type=module -e \
|
|
@@ -92,7 +92,7 @@ import {
|
|
|
92
92
|
ensureHermesOpportunitySequencesCron,
|
|
93
93
|
ensureHermesSnapshotCron,
|
|
94
94
|
markHermesSnapshotDirty,
|
|
95
|
-
|
|
95
|
+
linkHermesState,
|
|
96
96
|
migrateLegacyHermesUserState,
|
|
97
97
|
quarantineLegacyLightfieldVenv,
|
|
98
98
|
reconcileHermesSnapshot,
|
|
@@ -1326,7 +1326,10 @@ async function materializeAdminProfile({
|
|
|
1326
1326
|
}
|
|
1327
1327
|
);
|
|
1328
1328
|
}
|
|
1329
|
-
|
|
1329
|
+
// The gateway and endpoint relay are stopped before materialization.
|
|
1330
|
+
// Reuse durable inodes on this volume, as Customer profiles do, so a
|
|
1331
|
+
// large conversation DB cannot exhaust disk during an upgrade.
|
|
1332
|
+
linkHermesState(profileHome, stageRoot, {
|
|
1330
1333
|
skipSourceTopLevelNames:
|
|
1331
1334
|
liveSkillsIdentity === null ? [] : ["skills"],
|
|
1332
1335
|
});
|
|
@@ -2943,7 +2946,7 @@ async function flushHermesSnapshot({
|
|
|
2943
2946
|
profileId,
|
|
2944
2947
|
profileRoot,
|
|
2945
2948
|
hermesRoot: DATA_ROOT,
|
|
2946
|
-
hermesVersion: "0.21.
|
|
2949
|
+
hermesVersion: "0.21.5",
|
|
2947
2950
|
debounceMs: 0,
|
|
2948
2951
|
operationIdentity,
|
|
2949
2952
|
upload: ({
|
|
@@ -2960,7 +2963,7 @@ async function flushHermesSnapshot({
|
|
|
2960
2963
|
{
|
|
2961
2964
|
archiveDigest,
|
|
2962
2965
|
archiveBytes,
|
|
2963
|
-
hermesVersion: "0.21.
|
|
2966
|
+
hermesVersion: "0.21.5",
|
|
2964
2967
|
sourceProfileId,
|
|
2965
2968
|
...v2,
|
|
2966
2969
|
},
|
|
@@ -3939,13 +3942,13 @@ async function runAdminProduction() {
|
|
|
3939
3942
|
profileId: activeLaunch.profile.profile,
|
|
3940
3943
|
profileRoot: activeLaunch.profile.profileHome,
|
|
3941
3944
|
hermesRoot: DATA_ROOT,
|
|
3942
|
-
hermesVersion: "0.21.
|
|
3945
|
+
hermesVersion: "0.21.5",
|
|
3943
3946
|
upload: ({ archiveDigest, archiveBytes, sourceProfileId, bytes }) =>
|
|
3944
3947
|
client.putMemorySnapshot(
|
|
3945
3948
|
{
|
|
3946
3949
|
archiveDigest,
|
|
3947
3950
|
archiveBytes,
|
|
3948
|
-
hermesVersion: "0.21.
|
|
3951
|
+
hermesVersion: "0.21.5",
|
|
3949
3952
|
sourceProfileId,
|
|
3950
3953
|
},
|
|
3951
3954
|
bytes
|
|
@@ -4115,7 +4118,7 @@ async function runAdminProduction() {
|
|
|
4115
4118
|
profileId: basename(profileContract.profileHome),
|
|
4116
4119
|
profileRoot: profileContract.profileHome,
|
|
4117
4120
|
hermesRoot: DATA_ROOT,
|
|
4118
|
-
hermesVersion: "0.21.
|
|
4121
|
+
hermesVersion: "0.21.5",
|
|
4119
4122
|
fetchLatest: () => client.getMemorySnapshot(),
|
|
4120
4123
|
})
|
|
4121
4124
|
);
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
# syntax=docker/dockerfile:1.7
|
|
2
|
-
ARG HERMES_IMAGE=nousresearch/hermes-agent@sha256:
|
|
2
|
+
ARG HERMES_IMAGE=nousresearch/hermes-agent@sha256:fca358f12efd65bfaaca05884166f15c0e2788375ca30d77061ac1ebc96452b7
|
|
3
3
|
FROM ${HERMES_IMAGE}
|
|
4
4
|
|
|
5
5
|
USER root
|
|
@@ -8,16 +8,16 @@ ENV PLAYWRIGHT_BROWSERS_PATH=/opt/hermes/.playwright
|
|
|
8
8
|
|
|
9
9
|
ARG MCP_PACKAGE=@sellable/mcp@0.1.941
|
|
10
10
|
ARG MCP_INTEGRITY=sha512-Dhi+r50kwZa0E6iskB7dmDM/kCe9woEExLXxfLg8jf9LSKj86V5AiC0jhpS7euoo/lvY5e9m2a0BlTV9wqFxRQ==
|
|
11
|
-
ARG INSTALLER_PACKAGE=@sellable/install@0.1.
|
|
11
|
+
ARG INSTALLER_PACKAGE=@sellable/install@0.1.768-wip.hermes-20260925.4
|
|
12
12
|
ARG ADMIN_MCP_PACKAGE=@sellable/admin-mcp@0.1.202
|
|
13
13
|
ARG ADMIN_MCP_INTEGRITY=sha512-ym3aye/0vQ8tfULJlKz9JFOxvIQsl1G+n3np+TTgK/tecwNblBo/j3AkTnRqH9iomKzPbZzP+n4tEQsvsU8ByA==
|
|
14
14
|
ARG TUS_JS_CLIENT_VERSION=4.3.1
|
|
15
15
|
ARG YAML_VERSION=2.9.0
|
|
16
|
-
ARG HERMES_VERSION=0.21.
|
|
16
|
+
ARG HERMES_VERSION=0.21.5
|
|
17
17
|
ARG AGENT_BROWSER_VERSION=0.26.0
|
|
18
18
|
ARG TIRITH_VERSION=0.3.3
|
|
19
|
-
ARG PLAYWRIGHT_VERSION=1.
|
|
20
|
-
ARG PLAYWRIGHT_BROWSER_REVISION=
|
|
19
|
+
ARG PLAYWRIGHT_VERSION=1.63.0
|
|
20
|
+
ARG PLAYWRIGHT_BROWSER_REVISION=1243
|
|
21
21
|
ARG TIRITH_ARCHIVE_SHA256=6cdbe35e8f9ccf42e70ad95b501c93cd218ac18201c3df958d54f6ba0d995ce2
|
|
22
22
|
ARG DEFAULT_PROFILE_BUNDLE_FIXTURE_VERSION=1
|
|
23
23
|
ARG DEFAULT_PROFILE_BUNDLE_VERSION=4
|
|
@@ -114,7 +114,7 @@ RUN set -eux; \
|
|
|
114
114
|
'const fs=require("fs"); const manifest=JSON.parse(fs.readFileSync("/usr/local/share/sellable-agent/default-profile-bundle/manifest.json")); if(String(manifest.bundleVersion)!==process.argv[1] || manifest.bundleDigest!==process.argv[2]) process.exit(1);' \
|
|
115
115
|
"${DEFAULT_PROFILE_BUNDLE_VERSION}" "${DEFAULT_PROFILE_BUNDLE_DIGEST}" \
|
|
116
116
|
&& node --input-type=module -e \
|
|
117
|
-
'import { installHermesAgentBridge,
|
|
117
|
+
'import { installHermesAgentBridge, HERMES_AGENT_BRIDGE_DEDICATED_V0215_CONTRACT } from "/usr/local/lib/sellable-agent/hermes-bridge.mjs"; installHermesAgentBridge({ sourceRoot: "/opt/hermes", contract: HERMES_AGENT_BRIDGE_DEDICATED_V0215_CONTRACT });' \
|
|
118
118
|
&& node --input-type=module -e \
|
|
119
119
|
'await import("/usr/local/lib/sellable-agent/fly-runtime-identity.mjs");' \
|
|
120
120
|
&& node --input-type=module -e \
|
|
@@ -120,9 +120,9 @@ const RUNTIME_GENERATION = Number(
|
|
|
120
120
|
"0"
|
|
121
121
|
);
|
|
122
122
|
const BOOT_SESSION_ID = randomUUID();
|
|
123
|
-
const HERMES_VERSION = process.env.SELLABLE_AGENT_HERMES_VERSION ?? "0.21.
|
|
123
|
+
const HERMES_VERSION = process.env.SELLABLE_AGENT_HERMES_VERSION ?? "0.21.5";
|
|
124
124
|
const INSTALLER_PACKAGE =
|
|
125
|
-
process.env.SELLABLE_AGENT_INSTALLER_PACKAGE ?? "@sellable/install@0.1.
|
|
125
|
+
process.env.SELLABLE_AGENT_INSTALLER_PACKAGE ?? "@sellable/install@0.1.768-wip.hermes-20260925.4";
|
|
126
126
|
const MCP_PACKAGE =
|
|
127
127
|
process.env.SELLABLE_AGENT_MCP_PACKAGE ?? "@sellable/mcp@0.1.941";
|
|
128
128
|
export const ENDPOINT_MAX_CONCURRENT_RUNS = 10;
|
|
@@ -331,12 +331,18 @@ export function customerRuntimeDoctorFailureCode(
|
|
|
331
331
|
|
|
332
332
|
/**
|
|
333
333
|
* @param {string} action
|
|
334
|
-
* @param {{ runtimeAuthorityScope?: "ASSIGNED" | "CANDIDATE" | null }} [options]
|
|
334
|
+
* @param {{ runtimeAuthorityScope?: "ASSIGNED" | "CANDIDATE" | null, directReadinessProven?: boolean }} [options]
|
|
335
335
|
*/
|
|
336
336
|
export function customerRuntimeDoctorRequired(
|
|
337
337
|
action,
|
|
338
|
-
{ runtimeAuthorityScope = null } = {}
|
|
338
|
+
{ runtimeAuthorityScope = null, directReadinessProven = false } = {}
|
|
339
339
|
) {
|
|
340
|
+
// A successful provisioned proof checks the pinned binaries, MCP and model
|
|
341
|
+
// credentials; proveApplication then requires Slack identity/socket and the
|
|
342
|
+
// authenticated native API. Interactive doctor additionally requires a
|
|
343
|
+
// default-profile .env and a ~/.local/bin shim that these containers do not
|
|
344
|
+
// use. Those workstation checks must not reject an otherwise proven restart.
|
|
345
|
+
if (directReadinessProven) return false;
|
|
340
346
|
// START and candidate promotion already prove the binaries, model auth,
|
|
341
347
|
// Slack identities, gateway, private API, and native skills directly below.
|
|
342
348
|
// Keep the broad interactive diagnostic on assigned-runtime REFRESH only;
|
|
@@ -3436,6 +3442,7 @@ async function proveApplication({
|
|
|
3436
3442
|
const runtimeEnv = applicationRuntimeEnv({ desired, runtimeConfig, secrets });
|
|
3437
3443
|
const doctor = customerRuntimeDoctorRequired(action, {
|
|
3438
3444
|
runtimeAuthorityScope,
|
|
3445
|
+
directReadinessProven: true,
|
|
3439
3446
|
})
|
|
3440
3447
|
? await run(HERMES, ["doctor"], {
|
|
3441
3448
|
env: runtimeEnv,
|
|
@@ -14,13 +14,13 @@ const MAX_HISTORY_ITEMS = 64;
|
|
|
14
14
|
const MAX_EVENT_BYTES = 128 * 1024;
|
|
15
15
|
const MAX_CANONICAL_OUTPUT_BYTES = 48 * 1024;
|
|
16
16
|
const EXACT_FIXTURE_DIGEST =
|
|
17
|
-
"
|
|
17
|
+
"dc91130958d2d0181843d12b5073aa0df3b36c7d96718e149750aa5f692640ef";
|
|
18
18
|
|
|
19
19
|
export const HERMES_RUNS_FIXTURE_IDENTITY = Object.freeze({
|
|
20
20
|
schemaVersion: "sellable-hermes-api-capabilities/v1",
|
|
21
21
|
image:
|
|
22
|
-
"nousresearch/hermes-agent@sha256:
|
|
23
|
-
hermesVersion: "0.21.
|
|
22
|
+
"nousresearch/hermes-agent@sha256:fca358f12efd65bfaaca05884166f15c0e2788375ca30d77061ac1ebc96452b7",
|
|
23
|
+
hermesVersion: "0.21.5",
|
|
24
24
|
fixtureDigest: EXACT_FIXTURE_DIGEST,
|
|
25
25
|
origin: LOOPBACK_ORIGIN,
|
|
26
26
|
auth: "bearer",
|
|
@@ -80,7 +80,7 @@ function normalizedTimestamp(value) {
|
|
|
80
80
|
) {
|
|
81
81
|
return value;
|
|
82
82
|
}
|
|
83
|
-
// Hermes 0.21.
|
|
83
|
+
// Hermes 0.21.5's live /v1/runs implementation emits time.time() seconds,
|
|
84
84
|
// even though the captured fixture examples use ISO strings. Normalize that
|
|
85
85
|
// observed wire shape so known tool events do not collapse to UNKNOWN.
|
|
86
86
|
if (
|
|
@@ -559,7 +559,7 @@ export function createHermesRunsClient(options = {}) {
|
|
|
559
559
|
throw transportFailure("SUBMIT_AMBIGUOUS", error);
|
|
560
560
|
}
|
|
561
561
|
const value = await readBounded(response);
|
|
562
|
-
// Hermes 0.21.
|
|
562
|
+
// Hermes 0.21.5 emits 429 for its concurrency limiter and 503 while the
|
|
563
563
|
// gateway is draining. Both responses occur before it allocates a run,
|
|
564
564
|
// so retrying the identical request cannot duplicate a native attempt.
|
|
565
565
|
if (response.status === 429 || response.status === 503) {
|
|
@@ -476,6 +476,12 @@ export function buildNativeHermesLaunch({
|
|
|
476
476
|
"gateway",
|
|
477
477
|
"run",
|
|
478
478
|
"--replace",
|
|
479
|
+
// Each Fly Machine owns exactly one profile. Sellable supervises this
|
|
480
|
+
// foreground child and its credential descriptors; Hermes 0.21.5 must
|
|
481
|
+
// neither attach it to a host multiplexer nor redirect it to stock s6.
|
|
482
|
+
"--force",
|
|
483
|
+
"--no-supervise",
|
|
484
|
+
"--external-supervisor",
|
|
479
485
|
]),
|
|
480
486
|
cwd: resolvedProfileRoot,
|
|
481
487
|
env: Object.freeze({
|
|
@@ -1086,7 +1086,7 @@ export function createFlyCustomerControlClient({
|
|
|
1086
1086
|
Number.isSafeInteger(value?.archiveBytes) &&
|
|
1087
1087
|
value.archiveBytes > 0 &&
|
|
1088
1088
|
value.archiveBytes <= 512 * 1024 * 1024 &&
|
|
1089
|
-
value.hermesVersion === "0.21.
|
|
1089
|
+
value.hermesVersion === "0.21.5" &&
|
|
1090
1090
|
/^[A-Za-z0-9][A-Za-z0-9_-]{0,127}$/.test(value?.sourceProfileId ?? "");
|
|
1091
1091
|
const boundedSnapshotIdentity = (value) =>
|
|
1092
1092
|
/^[A-Za-z0-9][A-Za-z0-9_./:-]{0,255}$/.test(value ?? "");
|
|
@@ -751,6 +751,7 @@ def _sellable_agent_call_meta():
|
|
|
751
751
|
"HERMES_SESSION_CHAT_ID",
|
|
752
752
|
"HERMES_SESSION_USER_ID",
|
|
753
753
|
"HERMES_SESSION_MESSAGE_ID",
|
|
754
|
+
"HERMES_CRON_SESSION",
|
|
754
755
|
)
|
|
755
756
|
if any(os.getenv(name) for name in legacy_names):
|
|
756
757
|
raise RuntimeError("Sellable MCP identity must not come from process-global session variables")
|
|
@@ -760,11 +761,9 @@ def _sellable_agent_call_meta():
|
|
|
760
761
|
if not session_id:
|
|
761
762
|
raise RuntimeError("Sellable endpoint MCP calls require a bound Hermes session")
|
|
762
763
|
return {"sellableEndpoint": {"sessionId": session_id}}
|
|
763
|
-
if platform == "
|
|
764
|
-
|
|
765
|
-
|
|
766
|
-
# Native scheduled work uses the existing service credential without a
|
|
767
|
-
# Slack actor. The serving API still enforces workspace and actor gates.
|
|
764
|
+
if not platform and get_session_env("HERMES_CRON_SESSION", "").strip() == "1":
|
|
765
|
+
# Native _CronRunScope clears human routing and sets this task-local flag
|
|
766
|
+
# (Phase207 ADMIN766 smoke). The API still enforces service/workspace gates.
|
|
768
767
|
return None
|
|
769
768
|
if platform != "slack":
|
|
770
769
|
descriptor_path = os.getenv("SELLABLE_AGENT_TURN_DESCRIPTOR_PATH", "")
|
|
@@ -2179,7 +2178,8 @@ def getenv(name, default=""):
|
|
|
2179
2178
|
|
|
2180
2179
|
if (
|
|
2181
2180
|
patchKind === "skills-prompt-freshness-v020" ||
|
|
2182
|
-
patchKind === "skills-prompt-freshness-v021"
|
|
2181
|
+
patchKind === "skills-prompt-freshness-v021" ||
|
|
2182
|
+
patchKind === "skills-prompt-freshness-v0215"
|
|
2183
2183
|
) {
|
|
2184
2184
|
let patched = replaceExactlyOnce(
|
|
2185
2185
|
source,
|
|
@@ -2226,6 +2226,28 @@ def getenv(name, default=""):
|
|
|
2226
2226
|
].join("\n"),
|
|
2227
2227
|
"v0.20 prompt live signature"
|
|
2228
2228
|
);
|
|
2229
|
+
if (patchKind === "skills-prompt-freshness-v0215") {
|
|
2230
|
+
patched = replaceExactlyOnce(
|
|
2231
|
+
patched,
|
|
2232
|
+
" _oneshot_prompt_variant(),\n )\n snapshot = _load_skills_snapshot(skills_dir)",
|
|
2233
|
+
" _oneshot_prompt_variant(),\n live_signature,\n )\n snapshot = _load_skills_snapshot(skills_dir)",
|
|
2234
|
+
"v0.21.5 prompt signature cache key"
|
|
2235
|
+
);
|
|
2236
|
+
// Keep upstream oneshot partitions and app-gated cache bypass intact.
|
|
2237
|
+
return replaceExactlyOnce(
|
|
2238
|
+
patched,
|
|
2239
|
+
" with _SKILLS_PROMPT_CACHE_LOCK:\n cached = _SKILLS_PROMPT_CACHE.get(cache_key)",
|
|
2240
|
+
[
|
|
2241
|
+
" global _SELLABLE_AGENT_SKILLS_PROMPT_SIGNATURE",
|
|
2242
|
+
" with _SKILLS_PROMPT_CACHE_LOCK:",
|
|
2243
|
+
" if _SELLABLE_AGENT_SKILLS_PROMPT_SIGNATURE != live_signature:",
|
|
2244
|
+
" _SKILLS_PROMPT_CACHE.clear()",
|
|
2245
|
+
" _SELLABLE_AGENT_SKILLS_PROMPT_SIGNATURE = live_signature",
|
|
2246
|
+
" cached = _SKILLS_PROMPT_CACHE.get(cache_key)",
|
|
2247
|
+
].join("\n"),
|
|
2248
|
+
"v0.21.5 prompt cache invalidation"
|
|
2249
|
+
);
|
|
2250
|
+
}
|
|
2229
2251
|
patched = replaceExactlyOnce(
|
|
2230
2252
|
patched,
|
|
2231
2253
|
(patchKind === "skills-prompt-freshness-v021"
|
|
@@ -2474,7 +2496,7 @@ export const HERMES_AGENT_BRIDGE_DEDICATED_V020_CONTRACT = normalizeContract({
|
|
|
2474
2496
|
sourceSha256:
|
|
2475
2497
|
"8ce75e7f2d999edf6554a8f5a037289c885bc9427263da1cd6e3448e608fe20f",
|
|
2476
2498
|
patchedSha256:
|
|
2477
|
-
"
|
|
2499
|
+
"e4bf77633c8333d1f79310768c0824e8eaed87938ec7ffd2478050f12f5d36a6",
|
|
2478
2500
|
},
|
|
2479
2501
|
{
|
|
2480
2502
|
path: "gateway/run.py",
|
|
@@ -2549,7 +2571,7 @@ export const HERMES_AGENT_BRIDGE_DEDICATED_V021_CONTRACT = normalizeContract({
|
|
|
2549
2571
|
"path": "tools/mcp_tool_handlers.py",
|
|
2550
2572
|
"patchKind": "mcp-tool-endpoint-v021",
|
|
2551
2573
|
"sourceSha256": "e6af250f0fbfeb12a936c340a46f40f8d40332ed8bbc4eb63fded66e37aaa7bf",
|
|
2552
|
-
"patchedSha256": "
|
|
2574
|
+
"patchedSha256": "6c4765aad3074b6f8ad6951299edafa36cf536c9a9f0b57a48bdd541e3209790"
|
|
2553
2575
|
},
|
|
2554
2576
|
{
|
|
2555
2577
|
"path": "gateway/run.py",
|
|
@@ -2615,7 +2637,7 @@ export const HERMES_AGENT_BRIDGE_DEDICATED_V0213_CONTRACT = normalizeContract({
|
|
|
2615
2637
|
"path": "tools/mcp_tool_handlers.py",
|
|
2616
2638
|
"patchKind": "mcp-tool-endpoint-v021",
|
|
2617
2639
|
"sourceSha256": "c4713aa289c7ca17b53c0ae53ceb6a276321f6d36e259084974e8b5738b6a4dd",
|
|
2618
|
-
"patchedSha256": "
|
|
2640
|
+
"patchedSha256": "1bd801ebf1c6e17a0d81899b2ee0401f038ae4d1a493552f021a1b66fccf0e98"
|
|
2619
2641
|
},
|
|
2620
2642
|
{
|
|
2621
2643
|
"path": "gateway/run.py",
|
|
@@ -2669,6 +2691,84 @@ export const HERMES_AGENT_BRIDGE_DEDICATED_V0213_CONTRACT = normalizeContract({
|
|
|
2669
2691
|
"contractDigest": "75b5d16081dd2fdc5795d3b86d341f2ff341bf3c599e4c57de5ec14b3dd63ce0"
|
|
2670
2692
|
});
|
|
2671
2693
|
|
|
2694
|
+
export const HERMES_AGENT_BRIDGE_DEDICATED_V0215_CONTRACT = normalizeContract({
|
|
2695
|
+
"bridgeId": "sellable-agent-hermes-bridge/v1",
|
|
2696
|
+
"hermesVersion": "0.21.5",
|
|
2697
|
+
"versionFile": {
|
|
2698
|
+
"path": "hermes_cli/__init__.py",
|
|
2699
|
+
"sha256": "d05c98cd44e22781497a20cd968af0d9b8962406b909f1889168c624545b229e"
|
|
2700
|
+
},
|
|
2701
|
+
"files": [
|
|
2702
|
+
{
|
|
2703
|
+
"path": "gateway/config_env.py",
|
|
2704
|
+
"patchKind": "gateway-config-dedicated-v021",
|
|
2705
|
+
"sourceSha256": "5661d9cfb7d798d6c995b03727bdd4018669ae12c96d1e7a8f3c99a3ea85acc7",
|
|
2706
|
+
"patchedSha256": "cd8efa414e0313bca77d0d8093acc505d9f345b8fb48d734821e66027545bf57"
|
|
2707
|
+
},
|
|
2708
|
+
{
|
|
2709
|
+
"path": "plugins/platforms/slack/adapter.py",
|
|
2710
|
+
"patchKind": "slack-adapter-dedicated-v0213",
|
|
2711
|
+
"sourceSha256": "3f2ec0cef97964bf4cb1e9791c0917a03cd1e73bb0bc3293768680cd6302f613",
|
|
2712
|
+
"patchedSha256": "26cedfad352e8dadae82bebcedf8813ef948622a350b392ce99097a8ede2f056"
|
|
2713
|
+
},
|
|
2714
|
+
{
|
|
2715
|
+
"path": "tools/mcp_tool_handlers.py",
|
|
2716
|
+
"patchKind": "mcp-tool-endpoint-v021",
|
|
2717
|
+
"sourceSha256": "d1b4463309a2de351aaf6c7cd8f7a2a1e83f5e26dbe058371c9eeb9d0c567903",
|
|
2718
|
+
"patchedSha256": "61ceab8c24aef50e88d6c1dad1bbf80daed66f8950b05fb642525a62a0bb789c"
|
|
2719
|
+
},
|
|
2720
|
+
{
|
|
2721
|
+
"path": "gateway/run.py",
|
|
2722
|
+
"patchKind": "gateway-session-v021",
|
|
2723
|
+
"sourceSha256": "324f7095223816b865dd68a75dc83bfd1c3d101ac8c1c38dba69026dab2b6af1",
|
|
2724
|
+
"patchedSha256": "4b398b8c033e5aaba90b6ba312baf01e7d88d46a91843e64949ade0b65f2ade8"
|
|
2725
|
+
},
|
|
2726
|
+
{
|
|
2727
|
+
"path": "gateway/run_turn.py",
|
|
2728
|
+
"patchKind": "gateway-first-contact-v0213",
|
|
2729
|
+
"sourceSha256": "5bdee5c82c00e02f664516f9da0af99674e23493ec2a30eff06cb03afc6718a0",
|
|
2730
|
+
"patchedSha256": "0729145f27559df970c16d5be11e01ebce657874e4be1d9e151562042f5208c0"
|
|
2731
|
+
},
|
|
2732
|
+
{
|
|
2733
|
+
"path": "gateway/run_turn_runner.py",
|
|
2734
|
+
"patchKind": "gateway-provider-preflight-v021",
|
|
2735
|
+
"sourceSha256": "216bdca083b7d2bfae481d07bd0791a76834674b3614fd4ee0aafac5c58f30db",
|
|
2736
|
+
"patchedSha256": "7b6beabeed7b78781d142dcdb0eff4c0110263ee173f7696737c4c965e1c72ab"
|
|
2737
|
+
},
|
|
2738
|
+
{
|
|
2739
|
+
"path": "agent/turn_context.py",
|
|
2740
|
+
"patchKind": "turn-context-v021",
|
|
2741
|
+
"sourceSha256": "85f857dc3c317366d918516bc8b37a022f1020b34da0c3966a31bd289b2942e1",
|
|
2742
|
+
"patchedSha256": "a6487c43bc2d21f40e3a86fe31a9a0c2e4e603fff813f7c8429bbf5c22591648"
|
|
2743
|
+
},
|
|
2744
|
+
{
|
|
2745
|
+
"path": "cron/scheduler.py",
|
|
2746
|
+
"patchKind": "cron-scheduler-v020",
|
|
2747
|
+
"sourceSha256": "dcf0e6794a220e478584a21f786b8451b915fc7397d38eda357af1363249fa2a",
|
|
2748
|
+
"patchedSha256": "e98d197ce3d0b414184e3c746fe3814c213407da68ce0a46a8b4dd63a9054a11"
|
|
2749
|
+
},
|
|
2750
|
+
{
|
|
2751
|
+
"path": "tools/skills_tool.py",
|
|
2752
|
+
"patchKind": "skills-cache-freshness-v021",
|
|
2753
|
+
"sourceSha256": "0d47bda41ed9d1ec84856df3d336a42bb94161e89bd9a8b857e76ec76be9f7b7",
|
|
2754
|
+
"patchedSha256": "1bdc17603f3bb9fb34c5d04099dee2ca7d631eedc58b523bcd74d6e946dc9eb7"
|
|
2755
|
+
},
|
|
2756
|
+
{
|
|
2757
|
+
"path": "agent/prompt_builder.py",
|
|
2758
|
+
"patchKind": "skills-prompt-freshness-v0215",
|
|
2759
|
+
"sourceSha256": "64bc77a26641754b8c5ca76fc876687d3c9e81aad7816c2e76ce251a41121526",
|
|
2760
|
+
"patchedSha256": "56edefd92c50f38a3fed8d56b6fc02352f8e5892b43553ab277e3113606d25fb"
|
|
2761
|
+
},
|
|
2762
|
+
{
|
|
2763
|
+
"path": "gateway/platforms/api_server.py",
|
|
2764
|
+
"patchKind": "api-opener-stage-v021",
|
|
2765
|
+
"sourceSha256": "fa83a20bd4f9f3a90a3ac010db0a68f548259587946ea80b81b2f3253bafd5ec",
|
|
2766
|
+
"patchedSha256": "5289cc21e1804d0aaa49b117f32ea1a506375fa76459cdac8f5013f0566d05e1"
|
|
2767
|
+
}
|
|
2768
|
+
],
|
|
2769
|
+
"contractDigest": "d8b2ee47591435091a81a3e9913ba5acace2f9c1418cf75c0e23b4d0632e4024"
|
|
2770
|
+
});
|
|
2771
|
+
|
|
2672
2772
|
function assertRelativeContractPath(path) {
|
|
2673
2773
|
if (
|
|
2674
2774
|
!path ||
|
|
@@ -182,7 +182,7 @@ const LEGACY_HERMES_SNAPSHOT_SCRIPT = "scripts/hermes-memory-reconcile.sh";
|
|
|
182
182
|
|
|
183
183
|
const HERMES = "/opt/hermes/.venv/bin/hermes";
|
|
184
184
|
const HERMES_PYTHON = "/opt/hermes/.venv/bin/python";
|
|
185
|
-
const VERSION = "0.21.
|
|
185
|
+
const VERSION = "0.21.5";
|
|
186
186
|
const ID = /^[A-Za-z0-9][A-Za-z0-9_-]{0,127}$/;
|
|
187
187
|
const BOUNDED_ID = /^[A-Za-z0-9][A-Za-z0-9_./:-]{0,255}$/;
|
|
188
188
|
const SHA256 = /^[a-f0-9]{64}$/;
|
|
@@ -38,7 +38,7 @@ import { installAgentHostServices } from "./service-installer.mjs";
|
|
|
38
38
|
const PACKAGE_ROOT = resolve(dirname(fileURLToPath(import.meta.url)), "../..");
|
|
39
39
|
const VERSION = "sellable-agent-host-bootstrap/v1";
|
|
40
40
|
const RECEIPT_VERSION = "sellable-agent-host-registration/v1";
|
|
41
|
-
const INSTALLER_PACKAGE = "@sellable/install@0.1.
|
|
41
|
+
const INSTALLER_PACKAGE = "@sellable/install@0.1.768-wip.hermes-20260925.4";
|
|
42
42
|
const MCP_PACKAGE = "@sellable/mcp@0.1.941";
|
|
43
43
|
const HERMES_VERSION = "0.18.0";
|
|
44
44
|
const SHA256 = /^[a-f0-9]{64}$/;
|
|
@@ -1546,7 +1546,7 @@ export function compileClaimToProfileDesired(activeClaim, config) {
|
|
|
1546
1546
|
]) ||
|
|
1547
1547
|
pinned.hermesCli !== "hermes" ||
|
|
1548
1548
|
pinned.hermesVersion !== "0.18.0" ||
|
|
1549
|
-
pinned.installerPackage !== "@sellable/install@0.1.
|
|
1549
|
+
pinned.installerPackage !== "@sellable/install@0.1.768-wip.hermes-20260925.4" ||
|
|
1550
1550
|
pinned.mcpPackage !== "@sellable/mcp@0.1.941" ||
|
|
1551
1551
|
!Array.isArray(policy.toolInclude) ||
|
|
1552
1552
|
policy.toolInclude.length === 0 ||
|
|
@@ -211,9 +211,15 @@ function parseMarker(path) {
|
|
|
211
211
|
marker.models.length < 1 ||
|
|
212
212
|
(marker.version === MARKER_VERSION &&
|
|
213
213
|
(marker.models.length !== CURRENT_OPENROUTER_MODELS.length ||
|
|
214
|
-
marker.models.some((model, index) =>
|
|
215
|
-
|
|
216
|
-
|
|
214
|
+
marker.models.some((model, index) => {
|
|
215
|
+
const expected = CURRENT_OPENROUTER_MODELS[index];
|
|
216
|
+
// Preserve the activated effort during a rolling max -> high update.
|
|
217
|
+
return index === 0
|
|
218
|
+
? !exactKeys(model, MODEL_REASONING_KEYS) ||
|
|
219
|
+
model.id !== expected.id ||
|
|
220
|
+
!["max", "high"].includes(model.reasoningEffort)
|
|
221
|
+
: stableJson(model) !== stableJson(expected);
|
|
222
|
+
})))
|
|
217
223
|
) {
|
|
218
224
|
return null;
|
|
219
225
|
}
|
|
@@ -410,7 +416,7 @@ export function parseModelAuthRuntimeCredential(secret, options = {}) {
|
|
|
410
416
|
if (
|
|
411
417
|
!exactKeys(model, withReasoning ? MODEL_REASONING_KEYS : MODEL_KEYS) ||
|
|
412
418
|
model.id !== expected.id ||
|
|
413
|
-
(withReasoning && model.reasoningEffort
|
|
419
|
+
(withReasoning && !["max", "high"].includes(model.reasoningEffort))
|
|
414
420
|
) {
|
|
415
421
|
fail("model_auth_projection_incomplete");
|
|
416
422
|
}
|
|
@@ -450,7 +456,7 @@ export function modelAuthConfigOverlay(credential) {
|
|
|
450
456
|
...(credential.value.schemaVersion === MODEL_AUTH_RUNTIME_SCHEMA
|
|
451
457
|
? {
|
|
452
458
|
reasoning_overrides: Object.freeze({
|
|
453
|
-
"openai/gpt-5.6-luna":
|
|
459
|
+
"openai/gpt-5.6-luna": credential.value.openrouter.models[0].reasoningEffort,
|
|
454
460
|
}),
|
|
455
461
|
}
|
|
456
462
|
: {}),
|
|
@@ -663,7 +669,7 @@ export function readModelAuthMaterialization({ authStorePath, markerPath }) {
|
|
|
663
669
|
? {
|
|
664
670
|
models: Object.freeze(marker.models.map((model) => Object.freeze({ ...model }))),
|
|
665
671
|
reasoningOverrides: Object.freeze({
|
|
666
|
-
"openai/gpt-5.6-luna":
|
|
672
|
+
"openai/gpt-5.6-luna": marker.models[0].reasoningEffort,
|
|
667
673
|
}),
|
|
668
674
|
}
|
|
669
675
|
: {}),
|
|
@@ -726,6 +732,6 @@ export function modelAuthSelectionObservation(readback) {
|
|
|
726
732
|
provider,
|
|
727
733
|
modelId,
|
|
728
734
|
reasoningEffort:
|
|
729
|
-
modelId
|
|
735
|
+
readback.reasoningOverrides?.[modelId] ?? MODEL_AUTH_REASONING_EFFORT,
|
|
730
736
|
});
|
|
731
737
|
}
|
|
@@ -312,7 +312,7 @@ function validateDesired(desired) {
|
|
|
312
312
|
desired.serviceCredentialGeneration < 1 ||
|
|
313
313
|
desired.hermesCli !== "hermes" ||
|
|
314
314
|
desired.hermesVersion !== "0.18.0" ||
|
|
315
|
-
desired.installerPackage !== "@sellable/install@0.1.
|
|
315
|
+
desired.installerPackage !== "@sellable/install@0.1.768-wip.hermes-20260925.4" ||
|
|
316
316
|
desired.mcpPackage !== "@sellable/mcp@0.1.941" ||
|
|
317
317
|
!Array.isArray(desired.toolInclude) ||
|
|
318
318
|
desired.toolInclude.length === 0 ||
|
|
@@ -2566,7 +2566,7 @@ function validateNativeSlackDesired(desired) {
|
|
|
2566
2566
|
!SHA256.test(desired.accessPolicyHash ?? "") ||
|
|
2567
2567
|
!SHA256.test(desired.runtimeDesiredHash ?? "") ||
|
|
2568
2568
|
!FINGERPRINT.test(desired.apiServerKeyFingerprint ?? "") ||
|
|
2569
|
-
desired.hermesVersion !== "0.21.
|
|
2569
|
+
desired.hermesVersion !== "0.21.5" ||
|
|
2570
2570
|
!/^@sellable\/install@\d+\.\d+\.\d+(?:[-.A-Za-z0-9]+)?$/.test(
|
|
2571
2571
|
desired.installerPackage ?? ""
|
|
2572
2572
|
) ||
|
|
@@ -25,7 +25,7 @@ import { fileURLToPath } from "node:url";
|
|
|
25
25
|
import { deriveContainedProfileId } from "./profile-materializer.mjs";
|
|
26
26
|
|
|
27
27
|
export const PROVISIONING_ACTION = "PROVISION_HERMES_PROFILE";
|
|
28
|
-
export const PINNED_INSTALL_PACKAGE = "@sellable/install@0.1.
|
|
28
|
+
export const PINNED_INSTALL_PACKAGE = "@sellable/install@0.1.768-wip.hermes-20260925.4";
|
|
29
29
|
export const PINNED_MCP_PACKAGE = "@sellable/mcp@0.1.941";
|
|
30
30
|
const PINNED_INSTALL_VERSION = PINNED_INSTALL_PACKAGE.slice(
|
|
31
31
|
PINNED_INSTALL_PACKAGE.lastIndexOf("@") + 1
|