@sellable/install 0.1.484 → 0.1.486-wip.phase169.20260804.2
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 +2 -2
- package/lib/sellable-agent/admin-runtime-reconciler.mjs +1 -5
- package/lib/sellable-agent/fly-admin-image/Dockerfile +4 -0
- package/lib/sellable-agent/fly-admin-image/admin-runtime.mjs +327 -86
- package/lib/sellable-agent/fly-customer-image/Dockerfile +2 -2
- package/lib/sellable-agent/fly-customer-image/customer-runtime.mjs +224 -70
- package/lib/sellable-agent/fly-customer-image/model-auth-store.mjs +6 -143
- package/lib/sellable-agent/fly-customer-model.mjs +16 -157
- 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 +574 -0
- package/lib/sellable-agent/model-health-reporter.mjs +377 -0
- package/lib/sellable-agent/profile-materializer.mjs +17 -2
- package/lib/sellable-agent/provisioning-adapter.mjs +4 -4
- package/package.json +1 -1
|
@@ -39,8 +39,12 @@ import {
|
|
|
39
39
|
} from "../admin-artifact/node_modules/@sellable/admin-install/lib/hermes-admin-profile-factory.mjs";
|
|
40
40
|
import {
|
|
41
41
|
evaluateModelAuthReadback,
|
|
42
|
-
|
|
43
|
-
|
|
42
|
+
modelAuthConfigOverlay,
|
|
43
|
+
parseModelAuthRuntimeCredential,
|
|
44
|
+
readModelAuthMaterialization,
|
|
45
|
+
reconcileHermesModelAuth,
|
|
46
|
+
} from "../model-auth-reconciler.mjs";
|
|
47
|
+
import { createModelHealthReporter } from "../model-health-reporter.mjs";
|
|
44
48
|
import {
|
|
45
49
|
buildAdminAgentServiceEnvironment,
|
|
46
50
|
buildNativeHermesLaunch,
|
|
@@ -571,10 +575,40 @@ function profilePackageReceipt(
|
|
|
571
575
|
};
|
|
572
576
|
}
|
|
573
577
|
|
|
578
|
+
function installAdminModelConfig(profileRoot, modelConfig) {
|
|
579
|
+
const path = join(profileRoot, "config.yaml");
|
|
580
|
+
const stat = lstatSync(path);
|
|
581
|
+
if (stat.isSymbolicLink() || !stat.isFile()) {
|
|
582
|
+
throw new Error("admin_model_config_rejected");
|
|
583
|
+
}
|
|
584
|
+
const document = parseDocument(readFileSync(path, "utf8"));
|
|
585
|
+
if (document.errors.length > 0) {
|
|
586
|
+
throw new Error("admin_model_config_rejected");
|
|
587
|
+
}
|
|
588
|
+
document.set("model", modelConfig.model);
|
|
589
|
+
document.set(
|
|
590
|
+
"credential_pool_strategies",
|
|
591
|
+
modelConfig.credential_pool_strategies
|
|
592
|
+
);
|
|
593
|
+
document.set("fallback_providers", modelConfig.fallback_providers);
|
|
594
|
+
atomicPrivateFile(path, document.toString());
|
|
595
|
+
const readback = parseDocument(readFileSync(path, "utf8")).toJS();
|
|
596
|
+
if (
|
|
597
|
+
canonicalJson(readback.model) !== canonicalJson(modelConfig.model) ||
|
|
598
|
+
canonicalJson(readback.credential_pool_strategies) !==
|
|
599
|
+
canonicalJson(modelConfig.credential_pool_strategies) ||
|
|
600
|
+
canonicalJson(readback.fallback_providers) !==
|
|
601
|
+
canonicalJson(modelConfig.fallback_providers)
|
|
602
|
+
) {
|
|
603
|
+
throw new Error("admin_model_config_rejected");
|
|
604
|
+
}
|
|
605
|
+
}
|
|
606
|
+
|
|
574
607
|
async function materializeAdminProfile({
|
|
575
608
|
profileContract,
|
|
576
609
|
settingsRoot,
|
|
577
610
|
rootAuthPath,
|
|
611
|
+
modelConfig,
|
|
578
612
|
productConfigPath,
|
|
579
613
|
soul,
|
|
580
614
|
slack = null,
|
|
@@ -659,6 +693,7 @@ async function materializeAdminProfile({
|
|
|
659
693
|
return { ok: true, ...proof };
|
|
660
694
|
},
|
|
661
695
|
});
|
|
696
|
+
installAdminModelConfig(stageRoot, modelConfig);
|
|
662
697
|
mergeHermesState(profileHome, stageRoot);
|
|
663
698
|
installAdminHermesMemoryHook(stageRoot);
|
|
664
699
|
stageAdminRuntimeTree(stageRoot);
|
|
@@ -924,25 +959,43 @@ function installRuntimeSecrets({ claim, secrets, desiredLifecycle }) {
|
|
|
924
959
|
privateDirectory(SECRET_ROOT);
|
|
925
960
|
const modelAuthority = claim?.runtimeContract?.model;
|
|
926
961
|
const modelEnvelope = claim?.secretEnvelopes?.modelCodex;
|
|
962
|
+
const modelTuple = claim?.adminRuntimeGeneration?.tuple;
|
|
927
963
|
if (
|
|
928
964
|
modelAuthority?.provider !== "codex" ||
|
|
929
|
-
|
|
930
|
-
modelAuthority.
|
|
965
|
+
!/^[A-Za-z0-9_.:-]{1,256}$/.test(modelAuthority.activationId ?? "") ||
|
|
966
|
+
!Number.isSafeInteger(modelAuthority.bundleGeneration) ||
|
|
967
|
+
modelAuthority.bundleGeneration < 1 ||
|
|
968
|
+
!/^[a-f0-9]{64}$/.test(modelAuthority.policyHash ?? "") ||
|
|
931
969
|
!/^[a-f0-9]{16}$/.test(modelAuthority.credentialFingerprint ?? "") ||
|
|
932
|
-
modelAuthority.
|
|
970
|
+
modelAuthority.bundleGeneration !== modelEnvelope?.generation ||
|
|
933
971
|
modelAuthority.credentialFingerprint !== modelEnvelope?.fingerprint ||
|
|
972
|
+
modelEnvelope?.activationId !== modelAuthority.activationId ||
|
|
973
|
+
modelEnvelope?.bundleGeneration !== modelAuthority.bundleGeneration ||
|
|
974
|
+
modelEnvelope?.policyHash !== modelAuthority.policyHash ||
|
|
975
|
+
modelTuple?.modelAuthActivationId !== modelAuthority.activationId ||
|
|
976
|
+
modelTuple?.modelAuthBundleGeneration !== modelAuthority.bundleGeneration ||
|
|
977
|
+
modelTuple?.modelAuthPolicyHash !== modelAuthority.policyHash ||
|
|
934
978
|
!/^[A-Za-z0-9_-]{1,128}$/.test(claim?.operation?.profileId ?? "")
|
|
935
979
|
) {
|
|
936
980
|
throw new Error("admin_model_auth_identity_rejected");
|
|
937
981
|
}
|
|
938
|
-
const model =
|
|
982
|
+
const model = parseModelAuthRuntimeCredential(secrets.modelCodex);
|
|
983
|
+
if (
|
|
984
|
+
model.activationId !== modelAuthority.activationId ||
|
|
985
|
+
model.bundleGeneration !== modelAuthority.bundleGeneration ||
|
|
986
|
+
model.policyHash !== modelAuthority.policyHash
|
|
987
|
+
) {
|
|
988
|
+
throw new Error("admin_model_auth_identity_rejected");
|
|
989
|
+
}
|
|
939
990
|
const rootAuthPath = join(DATA_ROOT, "auth.json");
|
|
991
|
+
const markerPath = join(RUNTIME_ROOT, "model-auth-source.json");
|
|
940
992
|
const localAuthPath = join(
|
|
941
993
|
PROFILES_ROOT,
|
|
942
994
|
claim.operation.profileId,
|
|
943
995
|
"auth.json"
|
|
944
996
|
);
|
|
945
997
|
const identityPath = join(RUNTIME_ROOT, "model-auth-identity.json");
|
|
998
|
+
const modelBundlePath = join(SECRET_ROOT, "model-auth-runtime-v2.json");
|
|
946
999
|
const validateAuthFile = (path) => {
|
|
947
1000
|
const stat = lstatSync(path);
|
|
948
1001
|
if (stat.isSymbolicLink() || !stat.isFile() || (stat.mode & 0o077) !== 0) {
|
|
@@ -953,57 +1006,32 @@ function installRuntimeSecrets({ claim, secrets, desiredLifecycle }) {
|
|
|
953
1006
|
validateAuthFile(localAuthPath);
|
|
954
1007
|
rmSync(localAuthPath, { force: true });
|
|
955
1008
|
}
|
|
956
|
-
|
|
957
|
-
|
|
958
|
-
|
|
959
|
-
|
|
960
|
-
|
|
961
|
-
|
|
962
|
-
|
|
963
|
-
|
|
964
|
-
|
|
965
|
-
|
|
966
|
-
|
|
967
|
-
|
|
968
|
-
|
|
969
|
-
priorIdentity.credentialGeneration < 1 ||
|
|
970
|
-
!/^[a-f0-9]{16}$/.test(priorIdentity.credentialFingerprint ?? "") ||
|
|
971
|
-
Object.keys(priorIdentity).sort().join("\0") !==
|
|
972
|
-
[
|
|
973
|
-
"credentialFingerprint",
|
|
974
|
-
"credentialGeneration",
|
|
975
|
-
"provider",
|
|
976
|
-
"schemaVersion",
|
|
977
|
-
]
|
|
978
|
-
.sort()
|
|
979
|
-
.join("\0")
|
|
980
|
-
) {
|
|
981
|
-
throw new Error("admin_model_auth_identity_rejected");
|
|
982
|
-
}
|
|
983
|
-
priorCredentialGeneration = priorIdentity.credentialGeneration;
|
|
984
|
-
}
|
|
985
|
-
const replaceRootAuth =
|
|
986
|
-
priorCredentialGeneration === null ||
|
|
987
|
-
priorCredentialGeneration !== modelAuthority.credentialGeneration ||
|
|
988
|
-
!existsSync(rootAuthPath);
|
|
989
|
-
if (existsSync(rootAuthPath)) {
|
|
990
|
-
validateAuthFile(rootAuthPath);
|
|
991
|
-
if (replaceRootAuth) rmSync(rootAuthPath, { force: true });
|
|
992
|
-
}
|
|
993
|
-
if (replaceRootAuth) {
|
|
994
|
-
atomicPrivateFile(rootAuthPath, model.hermesRootAuthJson);
|
|
995
|
-
} else {
|
|
996
|
-
// Hermes may refresh the pooled OAuth record in place. Preserve that
|
|
997
|
-
// native state until the server advances the credential generation.
|
|
998
|
-
chmodSync(rootAuthPath, 0o600);
|
|
1009
|
+
atomicPrivateFile(modelBundlePath, model.authJson);
|
|
1010
|
+
const modelAuthState = reconcileHermesModelAuth({
|
|
1011
|
+
authStorePath: rootAuthPath,
|
|
1012
|
+
markerPath,
|
|
1013
|
+
credential: model,
|
|
1014
|
+
lifecycle: desiredLifecycle,
|
|
1015
|
+
});
|
|
1016
|
+
const profileAuthPath =
|
|
1017
|
+
desiredLifecycle === "ON"
|
|
1018
|
+
? rootAuthPath
|
|
1019
|
+
: join(SECRET_ROOT, "model-auth-pending-start.json");
|
|
1020
|
+
if (desiredLifecycle === "OFF") {
|
|
1021
|
+
atomicPrivateFile(profileAuthPath, model.hermesRootAuthJson);
|
|
999
1022
|
}
|
|
1000
1023
|
atomicPrivateFile(
|
|
1001
1024
|
identityPath,
|
|
1002
1025
|
`${JSON.stringify({
|
|
1003
|
-
schemaVersion: "sellable-admin-model-auth/
|
|
1026
|
+
schemaVersion: "sellable-admin-model-auth/v2",
|
|
1004
1027
|
provider: "codex",
|
|
1005
|
-
|
|
1028
|
+
activationId: modelAuthority.activationId,
|
|
1029
|
+
bundleGeneration: modelAuthority.bundleGeneration,
|
|
1030
|
+
policyHash: modelAuthority.policyHash,
|
|
1006
1031
|
credentialFingerprint: modelAuthority.credentialFingerprint,
|
|
1032
|
+
materializationStatus: modelAuthState.materialized
|
|
1033
|
+
? "current"
|
|
1034
|
+
: "pending_start",
|
|
1007
1035
|
})}\n`
|
|
1008
1036
|
);
|
|
1009
1037
|
atomicPrivateFile(join(SECRET_ROOT, "slack-app"), `${secrets.slackApp}\n`);
|
|
@@ -1026,13 +1054,70 @@ function installRuntimeSecrets({ claim, secrets, desiredLifecycle }) {
|
|
|
1026
1054
|
);
|
|
1027
1055
|
return {
|
|
1028
1056
|
rootAuthPath,
|
|
1057
|
+
profileAuthPath,
|
|
1058
|
+
markerPath,
|
|
1059
|
+
model,
|
|
1060
|
+
modelAuthState,
|
|
1061
|
+
modelConfig: modelAuthConfigOverlay(model),
|
|
1029
1062
|
productConfigPath,
|
|
1030
1063
|
runtimeGates,
|
|
1031
1064
|
slackSecretFile,
|
|
1032
1065
|
};
|
|
1033
1066
|
}
|
|
1034
1067
|
|
|
1035
|
-
function
|
|
1068
|
+
function pendingAdminModelAuthReadback(model) {
|
|
1069
|
+
return Object.freeze({
|
|
1070
|
+
schemaVersion: "sellable-agent-model-auth-readback/v2",
|
|
1071
|
+
activationId: model.activationId,
|
|
1072
|
+
bundleGeneration: model.bundleGeneration,
|
|
1073
|
+
policyHash: model.policyHash,
|
|
1074
|
+
provider: model.provider,
|
|
1075
|
+
model: model.model,
|
|
1076
|
+
fallbackDepth: model.value.openrouter.models.length,
|
|
1077
|
+
desiredStatus: "converged",
|
|
1078
|
+
materializedStatus: "pending_start",
|
|
1079
|
+
slots: Object.freeze(
|
|
1080
|
+
model.identity.slots.map((slot) =>
|
|
1081
|
+
Object.freeze({
|
|
1082
|
+
slotId: slot.slotId,
|
|
1083
|
+
grantFingerprint: slot.grantFingerprint,
|
|
1084
|
+
expiresAt: new Date(slot.expiresAt).toISOString(),
|
|
1085
|
+
state: "ok",
|
|
1086
|
+
lastErrorReason: null,
|
|
1087
|
+
lastErrorResetAt: null,
|
|
1088
|
+
})
|
|
1089
|
+
)
|
|
1090
|
+
),
|
|
1091
|
+
openrouter: Object.freeze({
|
|
1092
|
+
keyFingerprint: model.identity.openrouterKeyFingerprint,
|
|
1093
|
+
state: "ok",
|
|
1094
|
+
}),
|
|
1095
|
+
});
|
|
1096
|
+
}
|
|
1097
|
+
|
|
1098
|
+
function proveAdminModelAuth(profile, installed, desiredLifecycle) {
|
|
1099
|
+
if (desiredLifecycle === "OFF") {
|
|
1100
|
+
return Object.freeze({
|
|
1101
|
+
...pendingAdminModelAuthReadback(installed.model),
|
|
1102
|
+
source: "desired_converged_materialization_pending_start",
|
|
1103
|
+
sourceClass: "access_only_pool_pending_start",
|
|
1104
|
+
runtimeRefreshOwned: false,
|
|
1105
|
+
});
|
|
1106
|
+
}
|
|
1107
|
+
const materialization = readModelAuthMaterialization({
|
|
1108
|
+
authStorePath: installed.rootAuthPath,
|
|
1109
|
+
markerPath: installed.markerPath,
|
|
1110
|
+
});
|
|
1111
|
+
const verdict = evaluateModelAuthReadback(materialization, {
|
|
1112
|
+
activationId: installed.model.activationId,
|
|
1113
|
+
bundleGeneration: installed.model.bundleGeneration,
|
|
1114
|
+
policyHash: installed.model.policyHash,
|
|
1115
|
+
});
|
|
1116
|
+
if (!verdict.accepted) {
|
|
1117
|
+
throw new Error(
|
|
1118
|
+
`admin_model_auth_readback_rejected:${verdict.rejection ?? "unknown"}`
|
|
1119
|
+
);
|
|
1120
|
+
}
|
|
1036
1121
|
const environment = {
|
|
1037
1122
|
...process.env,
|
|
1038
1123
|
HOME: DATA_ROOT,
|
|
@@ -1049,12 +1134,10 @@ function proveAdminModelAuth(profile) {
|
|
|
1049
1134
|
"-c",
|
|
1050
1135
|
[
|
|
1051
1136
|
"import json",
|
|
1052
|
-
"from
|
|
1053
|
-
|
|
1054
|
-
"
|
|
1055
|
-
'
|
|
1056
|
-
'local_auth = get_hermes_home() / "auth.json"',
|
|
1057
|
-
'print(json.dumps({"provider": value.get("provider"), "source": value.get("source"), "source_class": "root_fallback" if root_auth.is_file() and not local_auth.exists() else "unexpected", "auth_mode": value.get("auth_mode"), "credential_present": bool(value.get("api_key")), "local_auth_entry_count": 0 if not local_auth.exists() else 1}))',
|
|
1137
|
+
"from agent.credential_pool import load_pool",
|
|
1138
|
+
'pool = load_pool("openai-codex")',
|
|
1139
|
+
"entry = pool.select()",
|
|
1140
|
+
'print(json.dumps({"provider": "openai-codex", "source": getattr(entry, "source", None), "source_class": "access_only_pool", "credential_id": getattr(entry, "id", None), "credential_present": bool(getattr(entry, "access_token", None)), "runtime_refresh_owned": bool(getattr(entry, "refresh_token", None))}))',
|
|
1058
1141
|
].join(";"),
|
|
1059
1142
|
],
|
|
1060
1143
|
{
|
|
@@ -1071,23 +1154,26 @@ function proveAdminModelAuth(profile) {
|
|
|
1071
1154
|
} catch {
|
|
1072
1155
|
readback = null;
|
|
1073
1156
|
}
|
|
1074
|
-
|
|
1075
|
-
|
|
1076
|
-
|
|
1077
|
-
|
|
1078
|
-
|
|
1079
|
-
|
|
1080
|
-
|
|
1081
|
-
|
|
1082
|
-
)
|
|
1157
|
+
if (
|
|
1158
|
+
probe.status !== 0 ||
|
|
1159
|
+
probe.error ||
|
|
1160
|
+
readback?.provider !== "openai-codex" ||
|
|
1161
|
+
readback?.source !== "manual:device_code" ||
|
|
1162
|
+
readback?.source_class !== "access_only_pool" ||
|
|
1163
|
+
!["dittto-primary", "kaigo-secondary"].includes(
|
|
1164
|
+
readback?.credential_id
|
|
1165
|
+
) ||
|
|
1166
|
+
readback?.credential_present !== true ||
|
|
1167
|
+
readback?.runtime_refresh_owned !== false
|
|
1168
|
+
) {
|
|
1169
|
+
throw new Error("access_only_snapshot_infeasible");
|
|
1083
1170
|
}
|
|
1084
1171
|
return Object.freeze({
|
|
1085
|
-
|
|
1172
|
+
...materialization,
|
|
1086
1173
|
source: readback.source,
|
|
1087
1174
|
sourceClass: readback.source_class,
|
|
1088
|
-
|
|
1089
|
-
|
|
1090
|
-
localAuthEntryCount: readback.local_auth_entry_count,
|
|
1175
|
+
selectedCredentialId: readback.credential_id,
|
|
1176
|
+
runtimeRefreshOwned: readback.runtime_refresh_owned,
|
|
1091
1177
|
});
|
|
1092
1178
|
}
|
|
1093
1179
|
|
|
@@ -1738,6 +1824,12 @@ function completionReceipt({
|
|
|
1738
1824
|
ciphertextDigest: recovery.ciphertextDigest,
|
|
1739
1825
|
locatorDigest: sha256(recovery.locator),
|
|
1740
1826
|
},
|
|
1827
|
+
modelAuth: {
|
|
1828
|
+
activationId: modelAuth.activationId,
|
|
1829
|
+
bundleGeneration: modelAuth.bundleGeneration,
|
|
1830
|
+
policyHash: modelAuth.policyHash,
|
|
1831
|
+
materializedStatus: modelAuth.materializedStatus,
|
|
1832
|
+
},
|
|
1741
1833
|
servers: profile.servers,
|
|
1742
1834
|
traffic: {
|
|
1743
1835
|
slackAccepted: false,
|
|
@@ -1772,7 +1864,13 @@ function completionReceipt({
|
|
|
1772
1864
|
{ code: "DUAL_MCP_PROVEN", status: "TRUE" },
|
|
1773
1865
|
{ code: "SETTINGS_GENERATION_PROVEN", status: "TRUE" },
|
|
1774
1866
|
{ code: "RECOVERY_GENERATION_PROVEN", status: "TRUE" },
|
|
1775
|
-
{
|
|
1867
|
+
{
|
|
1868
|
+
code:
|
|
1869
|
+
modelAuth.materializedStatus === "current"
|
|
1870
|
+
? "MODEL_AUTH_PROVEN"
|
|
1871
|
+
: "MODEL_AUTH_DESIRED_PENDING_START",
|
|
1872
|
+
status: "TRUE",
|
|
1873
|
+
},
|
|
1776
1874
|
{ code: "RUNTIME_GATES_PROVEN", status: "TRUE" },
|
|
1777
1875
|
{ code: "SLACK_TRAFFIC_DISABLED", status: "TRUE" },
|
|
1778
1876
|
{ code: "NO_BOOT_INSTALL", status: "TRUE" },
|
|
@@ -1818,6 +1916,47 @@ async function flushHermesSnapshot({ client, profileId, profileRoot }) {
|
|
|
1818
1916
|
}
|
|
1819
1917
|
}
|
|
1820
1918
|
|
|
1919
|
+
function adminModelHealthReporter({ identity, exchange, installed, claim }) {
|
|
1920
|
+
return createModelHealthReporter({
|
|
1921
|
+
origin: ORIGIN,
|
|
1922
|
+
identity: {
|
|
1923
|
+
kind: "ADMIN",
|
|
1924
|
+
runtimeGeneration: RUNTIME_GENERATION,
|
|
1925
|
+
workloadKeyHash: exchange.publicKeyHash,
|
|
1926
|
+
machineId: exchange.workerId,
|
|
1927
|
+
adminRuntimeGenerationId: claim.adminRuntimeGeneration.id,
|
|
1928
|
+
adminRuntimeGenerationFence: claim.adminRuntimeGeneration.fence,
|
|
1929
|
+
},
|
|
1930
|
+
observe: () =>
|
|
1931
|
+
readModelAuthMaterialization({
|
|
1932
|
+
authStorePath: installed.rootAuthPath,
|
|
1933
|
+
markerPath: installed.markerPath,
|
|
1934
|
+
}),
|
|
1935
|
+
authorize: (body) =>
|
|
1936
|
+
signedWorkerAuthorization({
|
|
1937
|
+
identity,
|
|
1938
|
+
exchange,
|
|
1939
|
+
verb: "model-health",
|
|
1940
|
+
body,
|
|
1941
|
+
now: new Date(),
|
|
1942
|
+
unbound: true,
|
|
1943
|
+
}),
|
|
1944
|
+
onError: (error) => {
|
|
1945
|
+
process.stderr.write(
|
|
1946
|
+
`${JSON.stringify({
|
|
1947
|
+
ok: false,
|
|
1948
|
+
code:
|
|
1949
|
+
error instanceof Error
|
|
1950
|
+
? error.message
|
|
1951
|
+
: "model_health_report_failed",
|
|
1952
|
+
})}\n`
|
|
1953
|
+
);
|
|
1954
|
+
},
|
|
1955
|
+
allowHttpLoopback: process.env.SELLABLE_AGENT_ALLOW_TEST_OIDC === "1",
|
|
1956
|
+
sequencePath: join(RUNTIME_ROOT, "model-health-sequence.json"),
|
|
1957
|
+
});
|
|
1958
|
+
}
|
|
1959
|
+
|
|
1821
1960
|
function desiredLifecycleForClaim(claim) {
|
|
1822
1961
|
switch (claim.operation.action) {
|
|
1823
1962
|
case "INSTANTIATE":
|
|
@@ -1996,23 +2135,64 @@ export async function runAdminCanary() {
|
|
|
1996
2135
|
atomicPrivateFile(join(sourceRoot, name), value);
|
|
1997
2136
|
}
|
|
1998
2137
|
const rootAuthPath = join(DATA_ROOT, "auth.json");
|
|
2138
|
+
const modelMarkerPath = join(canaryRoot, "model-auth-source.json");
|
|
1999
2139
|
const productConfigPath = join(SECRET_ROOT, "canary-product-config.json");
|
|
2000
2140
|
rmSync(rootAuthPath, { force: true });
|
|
2141
|
+
rmSync(modelMarkerPath, { force: true });
|
|
2001
2142
|
rmSync(productConfigPath, { force: true });
|
|
2002
|
-
const
|
|
2143
|
+
const canaryExpiresAt = new Date(Date.now() + 60 * 60 * 1000);
|
|
2144
|
+
const canaryJwt = (subject) =>
|
|
2145
|
+
[
|
|
2146
|
+
Buffer.from(JSON.stringify({ alg: "none", typ: "JWT" })).toString(
|
|
2147
|
+
"base64url"
|
|
2148
|
+
),
|
|
2149
|
+
Buffer.from(
|
|
2150
|
+
JSON.stringify({ sub: subject, exp: Math.floor(canaryExpiresAt / 1000) })
|
|
2151
|
+
).toString("base64url"),
|
|
2152
|
+
"phase158-canary-signature-placeholder",
|
|
2153
|
+
].join(".");
|
|
2154
|
+
const canaryModel = parseModelAuthRuntimeCredential(
|
|
2003
2155
|
JSON.stringify({
|
|
2004
|
-
|
|
2005
|
-
|
|
2006
|
-
|
|
2007
|
-
|
|
2008
|
-
|
|
2009
|
-
|
|
2010
|
-
|
|
2011
|
-
|
|
2156
|
+
schemaVersion: "sellable-agent-model-auth-runtime/v2",
|
|
2157
|
+
activationId: "phase158-canary-model-auth",
|
|
2158
|
+
bundleGeneration: 1,
|
|
2159
|
+
policyHash: "a".repeat(64),
|
|
2160
|
+
credentialPoolStrategy: "fill_first",
|
|
2161
|
+
codex: [
|
|
2162
|
+
{
|
|
2163
|
+
slotId: "dittto-primary",
|
|
2164
|
+
priority: 1,
|
|
2165
|
+
accessToken: canaryJwt("phase158-canary-dittto"),
|
|
2166
|
+
accountId: "phase158-canary-dittto",
|
|
2167
|
+
expiresAt: canaryExpiresAt.toISOString(),
|
|
2168
|
+
grantFingerprint: "a".repeat(16),
|
|
2169
|
+
},
|
|
2170
|
+
{
|
|
2171
|
+
slotId: "kaigo-secondary",
|
|
2172
|
+
priority: 2,
|
|
2173
|
+
accessToken: canaryJwt("phase158-canary-kaigo"),
|
|
2174
|
+
accountId: "phase158-canary-kaigo",
|
|
2175
|
+
expiresAt: canaryExpiresAt.toISOString(),
|
|
2176
|
+
grantFingerprint: "b".repeat(16),
|
|
2177
|
+
},
|
|
2178
|
+
],
|
|
2179
|
+
openrouter: {
|
|
2180
|
+
apiKey: "phase158-canary-openrouter-placeholder",
|
|
2181
|
+
keyFingerprint: "c".repeat(16),
|
|
2182
|
+
models: [
|
|
2183
|
+
"moonshotai/kimi-k3",
|
|
2184
|
+
"~deepseek/deepseek-v4-flash-latest",
|
|
2185
|
+
"z-ai/glm-5.2",
|
|
2186
|
+
],
|
|
2012
2187
|
},
|
|
2013
2188
|
})
|
|
2014
2189
|
);
|
|
2015
|
-
|
|
2190
|
+
const canaryModelAuthState = reconcileHermesModelAuth({
|
|
2191
|
+
authStorePath: rootAuthPath,
|
|
2192
|
+
markerPath: modelMarkerPath,
|
|
2193
|
+
credential: canaryModel,
|
|
2194
|
+
lifecycle: "ON",
|
|
2195
|
+
});
|
|
2016
2196
|
atomicPrivateFile(
|
|
2017
2197
|
productConfigPath,
|
|
2018
2198
|
`${JSON.stringify({
|
|
@@ -2199,6 +2379,7 @@ export async function runAdminCanary() {
|
|
|
2199
2379
|
profileContract,
|
|
2200
2380
|
settingsRoot,
|
|
2201
2381
|
rootAuthPath,
|
|
2382
|
+
modelConfig: modelAuthConfigOverlay(canaryModel),
|
|
2202
2383
|
productConfigPath,
|
|
2203
2384
|
soul: {
|
|
2204
2385
|
bytes: soulBytes,
|
|
@@ -2207,7 +2388,16 @@ export async function runAdminCanary() {
|
|
|
2207
2388
|
},
|
|
2208
2389
|
agentServiceEnv: agentServiceEnvironment,
|
|
2209
2390
|
});
|
|
2210
|
-
const modelAuth = proveAdminModelAuth(
|
|
2391
|
+
const modelAuth = proveAdminModelAuth(
|
|
2392
|
+
profile,
|
|
2393
|
+
{
|
|
2394
|
+
rootAuthPath,
|
|
2395
|
+
markerPath: modelMarkerPath,
|
|
2396
|
+
model: canaryModel,
|
|
2397
|
+
modelAuthState: canaryModelAuthState,
|
|
2398
|
+
},
|
|
2399
|
+
"ON"
|
|
2400
|
+
);
|
|
2211
2401
|
const attachmentHandoff = proveAdminAttachmentHandoff(profile);
|
|
2212
2402
|
const observedSettings = settingsProof(
|
|
2213
2403
|
settingsRoot,
|
|
@@ -2357,6 +2547,7 @@ async function runAdminProduction() {
|
|
|
2357
2547
|
const controller = new AbortController();
|
|
2358
2548
|
let activeGateway = null;
|
|
2359
2549
|
let activeLaunch = null;
|
|
2550
|
+
let activeModelHealthReporter = null;
|
|
2360
2551
|
let shutdownMemorySnapshot = null;
|
|
2361
2552
|
const beginShutdownSnapshot = () => {
|
|
2362
2553
|
if (!activeLaunch || shutdownMemorySnapshot) return;
|
|
@@ -2409,6 +2600,27 @@ async function runAdminProduction() {
|
|
|
2409
2600
|
});
|
|
2410
2601
|
exchange = renewed.exchange;
|
|
2411
2602
|
client = renewed.client;
|
|
2603
|
+
await activeModelHealthReporter?.stop();
|
|
2604
|
+
activeModelHealthReporter = null;
|
|
2605
|
+
if (activeLaunch) {
|
|
2606
|
+
activeModelHealthReporter = adminModelHealthReporter({
|
|
2607
|
+
identity,
|
|
2608
|
+
exchange,
|
|
2609
|
+
installed: activeLaunch.installed,
|
|
2610
|
+
claim: activeLaunch.claim,
|
|
2611
|
+
});
|
|
2612
|
+
activeModelHealthReporter.start("periodic").catch((reportError) => {
|
|
2613
|
+
process.stderr.write(
|
|
2614
|
+
`${JSON.stringify({
|
|
2615
|
+
ok: false,
|
|
2616
|
+
code:
|
|
2617
|
+
reportError instanceof Error
|
|
2618
|
+
? reportError.message
|
|
2619
|
+
: "model_health_report_failed",
|
|
2620
|
+
})}\n`
|
|
2621
|
+
);
|
|
2622
|
+
});
|
|
2623
|
+
}
|
|
2412
2624
|
failures = 0;
|
|
2413
2625
|
process.stderr.write(
|
|
2414
2626
|
`${JSON.stringify({
|
|
@@ -2466,6 +2678,8 @@ async function runAdminProduction() {
|
|
|
2466
2678
|
exchange,
|
|
2467
2679
|
client,
|
|
2468
2680
|
});
|
|
2681
|
+
await activeModelHealthReporter?.stop();
|
|
2682
|
+
activeModelHealthReporter = null;
|
|
2469
2683
|
await stopNativeGateway(activeGateway);
|
|
2470
2684
|
activeGateway = null;
|
|
2471
2685
|
activeLaunch = null;
|
|
@@ -2561,13 +2775,18 @@ async function runAdminProduction() {
|
|
|
2561
2775
|
const profile = await materializeAdminProfile({
|
|
2562
2776
|
profileContract,
|
|
2563
2777
|
settingsRoot: imported.receipt.generationRoot,
|
|
2564
|
-
rootAuthPath: installed.
|
|
2778
|
+
rootAuthPath: installed.profileAuthPath,
|
|
2779
|
+
modelConfig: installed.modelConfig,
|
|
2565
2780
|
productConfigPath: installed.productConfigPath,
|
|
2566
2781
|
soul: exactSoul(claim),
|
|
2567
2782
|
slack: nativeSlackProfileInput(claim, installed),
|
|
2568
2783
|
agentServiceEnv: adminAgentServiceEnvironment(claim),
|
|
2569
2784
|
});
|
|
2570
|
-
const modelAuth = proveAdminModelAuth(
|
|
2785
|
+
const modelAuth = proveAdminModelAuth(
|
|
2786
|
+
profile,
|
|
2787
|
+
installed,
|
|
2788
|
+
desiredLifecycle
|
|
2789
|
+
);
|
|
2571
2790
|
const memorySnapshot = await flushHermesSnapshot({
|
|
2572
2791
|
client,
|
|
2573
2792
|
profileId: profile.profile,
|
|
@@ -2608,7 +2827,7 @@ async function runAdminProduction() {
|
|
|
2608
2827
|
});
|
|
2609
2828
|
operationHeartbeat.assertHealthy();
|
|
2610
2829
|
const candidateLaunch =
|
|
2611
|
-
desiredLifecycle === "ON" ? { profile, claim } : null;
|
|
2830
|
+
desiredLifecycle === "ON" ? { profile, claim, installed } : null;
|
|
2612
2831
|
let candidateGateway = null;
|
|
2613
2832
|
try {
|
|
2614
2833
|
if (candidateLaunch) {
|
|
@@ -2631,6 +2850,27 @@ async function runAdminProduction() {
|
|
|
2631
2850
|
if (desiredLifecycle === "ON" && !activeLaunch) {
|
|
2632
2851
|
throw new Error("admin_native_gateway_completion_rejected");
|
|
2633
2852
|
}
|
|
2853
|
+
if (activeLaunch) {
|
|
2854
|
+
activeModelHealthReporter = adminModelHealthReporter({
|
|
2855
|
+
identity,
|
|
2856
|
+
exchange,
|
|
2857
|
+
installed: activeLaunch.installed,
|
|
2858
|
+
claim: activeLaunch.claim,
|
|
2859
|
+
});
|
|
2860
|
+
try {
|
|
2861
|
+
await activeModelHealthReporter.start("materialized");
|
|
2862
|
+
} catch (error) {
|
|
2863
|
+
process.stderr.write(
|
|
2864
|
+
`${JSON.stringify({
|
|
2865
|
+
ok: false,
|
|
2866
|
+
code:
|
|
2867
|
+
error instanceof Error
|
|
2868
|
+
? error.message
|
|
2869
|
+
: "model_health_report_failed",
|
|
2870
|
+
})}\n`
|
|
2871
|
+
);
|
|
2872
|
+
}
|
|
2873
|
+
}
|
|
2634
2874
|
await operationHeartbeat.stop();
|
|
2635
2875
|
operationHeartbeat = null;
|
|
2636
2876
|
failures = 0;
|
|
@@ -2663,6 +2903,7 @@ async function runAdminProduction() {
|
|
|
2663
2903
|
})}\n`
|
|
2664
2904
|
);
|
|
2665
2905
|
}
|
|
2906
|
+
await activeModelHealthReporter?.stop();
|
|
2666
2907
|
await stopNativeGateway(activeGateway);
|
|
2667
2908
|
clearRuntimeSecrets();
|
|
2668
2909
|
}
|
|
@@ -5,7 +5,7 @@ USER root
|
|
|
5
5
|
|
|
6
6
|
ARG MCP_PACKAGE=@sellable/mcp@0.1.805
|
|
7
7
|
ARG MCP_INTEGRITY=sha512-ULMGwWalb14SaMgxLeeiOWjavXpnONhdD8kAkvp7rJFdiL7s30VwXX+1j/aNwijiWXqqNQ1wcsXUPqk4eWpslg==
|
|
8
|
-
ARG INSTALLER_PACKAGE=@sellable/install@0.1.
|
|
8
|
+
ARG INSTALLER_PACKAGE=@sellable/install@0.1.486-wip.phase169.20260804.2
|
|
9
9
|
ARG TUS_JS_CLIENT_VERSION=4.3.1
|
|
10
10
|
ARG HERMES_VERSION=0.20.0
|
|
11
11
|
ARG MCP_TRUST_ROOT_B64
|
|
@@ -56,7 +56,7 @@ RUN test -n "${MCP_TRUST_ROOT_B64}" \
|
|
|
56
56
|
/etc/cont-init.d/02-reconcile-profiles \
|
|
57
57
|
&& npm cache clean --force
|
|
58
58
|
|
|
59
|
-
COPY mcp-context-proxy.mjs fly-customer-model.mjs fly-customer-worker.mjs profile-materializer.mjs hermes-bridge.mjs hermes-memory-snapshot.mjs fly-runtime-identity.mjs \
|
|
59
|
+
COPY mcp-context-proxy.mjs fly-customer-model.mjs fly-customer-worker.mjs profile-materializer.mjs model-auth-reconciler.mjs model-health-reporter.mjs hermes-bridge.mjs hermes-memory-snapshot.mjs fly-runtime-identity.mjs \
|
|
60
60
|
/usr/local/lib/sellable-agent/
|
|
61
61
|
COPY hermes-memory-dirty.mjs /opt/sellable/bin/hermes-memory-dirty
|
|
62
62
|
COPY hermes-memory-reconcile.sh /opt/sellable/share/hermes-memory-reconcile.sh
|