spawnfile 0.1.34 → 0.1.35

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.
Files changed (87) hide show
  1. package/dist/audit/readAudit.d.ts +3 -3
  2. package/dist/auth/profileStore.d.ts +3 -1
  3. package/dist/auth/profileStore.js +31 -30
  4. package/dist/auth/types.d.ts +16 -0
  5. package/dist/cli/authCommands.d.ts +1 -1
  6. package/dist/cli/authCommands.js +21 -1
  7. package/dist/cli/runCli.d.ts +2 -0
  8. package/dist/cli/runCli.js +2 -1
  9. package/dist/cli/trainingBooted.d.ts +2 -0
  10. package/dist/cli/trainingBooted.js +5 -1
  11. package/dist/compiler/containerDaimonBrokerRender.js +12 -2
  12. package/dist/compiler/containerDaimonGatewayRender.js +4 -0
  13. package/dist/compiler/containerDaimonUidEntrypointRender.js +3 -1
  14. package/dist/compiler/runProject.d.ts +2 -0
  15. package/dist/compiler/runProject.js +6 -5
  16. package/dist/compiler/runProjectAuth.js +4 -1
  17. package/dist/compiler/training/rewind/contract.d.ts +6 -6
  18. package/dist/compiler/training/trial/boot.d.ts +20 -1
  19. package/dist/compiler/training/trial/boot.js +102 -24
  20. package/dist/compiler/training/trial/docker.d.ts +2 -0
  21. package/dist/compiler/training/trial/docker.js +1 -1
  22. package/dist/compiler/training/trial/gateway.d.ts +5 -0
  23. package/dist/compiler/training/trial/gateway.js +18 -3
  24. package/dist/compiler/training/trial/homeLogin.d.ts +31 -0
  25. package/dist/compiler/training/trial/homeLogin.js +69 -0
  26. package/dist/compiler/training/trial/index.d.ts +5 -1
  27. package/dist/compiler/training/trial/index.js +5 -1
  28. package/dist/compiler/training/trial/judge.d.ts +15 -0
  29. package/dist/compiler/training/trial/judge.js +42 -0
  30. package/dist/compiler/training/trial/launcher.d.ts +28 -13
  31. package/dist/compiler/training/trial/launcher.js +168 -24
  32. package/dist/compiler/training/trial/login.d.ts +35 -0
  33. package/dist/compiler/training/trial/login.js +85 -0
  34. package/dist/compiler/training/trial/realmTurns.d.ts +20 -0
  35. package/dist/compiler/training/trial/realmTurns.js +69 -0
  36. package/dist/manifest/renderSpawnfile.js +2 -1
  37. package/dist/runtime/daimon/config.js +3 -3
  38. package/dist/runtime/daimon/engineDescriptors.generated.d.ts +1 -1
  39. package/dist/runtime/daimon/engineDescriptors.generated.js +1 -1
  40. package/dist/runtime/daimon/index.d.ts +1 -1
  41. package/dist/runtime/daimon/index.js +1 -1
  42. package/dist/runtime/daimon/runAuth.js +8 -0
  43. package/dist/runtime/daimon/subscriptionRealms.d.ts +18 -0
  44. package/dist/runtime/daimon/subscriptionRealms.js +14 -1
  45. package/dist/runtime/daimon/training/booted/adapter.d.ts +5 -1
  46. package/dist/runtime/daimon/training/booted/adapter.js +3 -2
  47. package/dist/runtime/daimon/training/booted/adapter.js.map +1 -1
  48. package/dist/runtime/daimon/training/booted/index.d.ts +3 -1
  49. package/dist/runtime/daimon/training/booted/index.js +2 -1
  50. package/dist/runtime/daimon/training/booted/index.js.map +1 -1
  51. package/dist/runtime/daimon/training/booted/judge.d.ts +39 -0
  52. package/dist/runtime/daimon/training/booted/judge.js +122 -0
  53. package/dist/runtime/daimon/training/booted/judge.js.map +1 -0
  54. package/dist/runtime/trainingGraderProviders.js +10 -4
  55. package/dist/runtime/trainingProviders.d.ts +4 -1
  56. package/dist/runtime/trainingProviders.js +13 -6
  57. package/dist/runtime/usageRequestLedger.d.ts +2 -0
  58. package/dist/runtime/usageRequestLedger.js +3 -1
  59. package/dist/shared/trainingLegacy/trainingLegacyHashDomains.d.ts +1 -0
  60. package/dist/shared/trainingLegacy/trainingLegacyHashDomains.js +1 -0
  61. package/dist/shared/trainingLegacy/trainingLegacyHashDomains.js.map +1 -1
  62. package/package.json +1 -1
  63. package/runtimes.yaml +5 -5
  64. package/dist/runtime/daimon/training/providers/codex-subscription/index.d.ts +0 -1
  65. package/dist/runtime/daimon/training/providers/codex-subscription/index.js +0 -2
  66. package/dist/runtime/daimon/training/providers/codex-subscription/index.js.map +0 -1
  67. package/dist/runtime/daimon/training/providers/codex-subscription/protocol.d.ts +0 -17
  68. package/dist/runtime/daimon/training/providers/codex-subscription/protocol.js +0 -80
  69. package/dist/runtime/daimon/training/providers/codex-subscription/protocol.js.map +0 -1
  70. package/dist/runtime/daimon/training/providers/codex-subscription/provider.d.ts +0 -12
  71. package/dist/runtime/daimon/training/providers/codex-subscription/provider.js +0 -125
  72. package/dist/runtime/daimon/training/providers/codex-subscription/provider.js.map +0 -1
  73. package/dist/runtime/daimon/training/providers/codex-subscription/strict-schema.d.ts +0 -6
  74. package/dist/runtime/daimon/training/providers/codex-subscription/strict-schema.js +0 -219
  75. package/dist/runtime/daimon/training/providers/codex-subscription/strict-schema.js.map +0 -1
  76. package/dist/runtime/daimon/training/providers/grok-subscription/cli.d.ts +0 -19
  77. package/dist/runtime/daimon/training/providers/grok-subscription/cli.js +0 -81
  78. package/dist/runtime/daimon/training/providers/grok-subscription/cli.js.map +0 -1
  79. package/dist/runtime/daimon/training/providers/grok-subscription/index.d.ts +0 -3
  80. package/dist/runtime/daimon/training/providers/grok-subscription/index.js +0 -4
  81. package/dist/runtime/daimon/training/providers/grok-subscription/index.js.map +0 -1
  82. package/dist/runtime/daimon/training/providers/grok-subscription/protocol.d.ts +0 -14
  83. package/dist/runtime/daimon/training/providers/grok-subscription/protocol.js +0 -89
  84. package/dist/runtime/daimon/training/providers/grok-subscription/protocol.js.map +0 -1
  85. package/dist/runtime/daimon/training/providers/grok-subscription/provider.d.ts +0 -9
  86. package/dist/runtime/daimon/training/providers/grok-subscription/provider.js +0 -37
  87. package/dist/runtime/daimon/training/providers/grok-subscription/provider.js.map +0 -1
@@ -1,44 +1,188 @@
1
1
  import { mkdir, mkdtemp } from "node:fs/promises";
2
2
  import path from "node:path";
3
+ import { daimonGatewayedEngines } from "../../../runtime/daimon/gateway.js";
4
+ import { getDaimonEngineDescriptor } from "../../../runtime/daimon/index.js";
3
5
  import { ensureNoopolisRunId } from "../../../runtime/index.js";
6
+ import { SpawnfileError } from "../../../shared/index.js";
4
7
  import { prepareTrial } from "./boot.js";
5
8
  import { createTrialDocker } from "./docker.js";
6
- import { startTrainingGateway } from "./gateway.js";
9
+ import { startTrainingGateway, trainingGatewayLogins } from "./gateway.js";
10
+ import { JUDGE_INSTRUCTIONS, writeJudgeAgent } from "./judge.js";
11
+ import { HOME_LOGIN_FILES } from "./homeLogin.js";
12
+ import { createRealmTurns } from "./realmTurns.js";
7
13
  /**
8
- * One training run's trials: each boot compiles and starts the subject's
9
- * one-agent organization, and every trial shares the run's single auth
10
- * gateway, started from the first trial's image on first use.
14
+ * One training run's containers: each trial boot compiles and starts the
15
+ * subject's one-agent organization, each judge is a tool-free one-agent
16
+ * organization booted the same way, and all of them share the run's single
17
+ * auth gateway, started from the first image on first use. The gateway holds
18
+ * every gatewayed login of the run's auth profile, so trials and judges on
19
+ * any engine reach it with one key.
11
20
  */
12
21
  export const createBootedTrialRun = (options) => {
13
22
  const docker = options.docker ?? createTrialDocker();
23
+ const turns = options.turns ?? createRealmTurns();
24
+ const prepare = options.prepare ?? prepareTrial;
14
25
  const runId = ensureNoopolisRunId();
26
+ const logins = trainingGatewayLogins(options.authProfile);
15
27
  let gateway;
16
- return {
17
- boot: async ({ trialId, instructions }) => {
18
- await mkdir(options.scratchRoot, { recursive: true });
19
- const prepared = await prepareTrial({ agentManifestPath: options.agentManifestPath, docker, instructions, trialId,
20
- directory: await mkdtemp(path.join(options.scratchRoot, "trial-")) });
21
- try {
22
- gateway ??= (async () => {
23
- const image = `spawnfile-training-gateway:${runId.replace(/[^A-Za-z0-9_.-]/gu, "-").slice(0, 100)}`;
24
- await docker(["tag", prepared.image, image]);
25
- return { image, gateway: await startTrainingGateway({ authProfile: options.authProfile, docker, engines: prepared.engines,
26
- image, runId, runtimeRoot: prepared.runtimeRoot }) };
27
- })();
28
- const booted = await prepared.boot((await gateway).gateway);
29
- return { wake: booted.wake, teardown: async () => { try {
30
- await booted.teardown();
28
+ const judges = new Map();
29
+ let closed = false;
30
+ /** The gateway this organization needs (null: no gatewayed engine), started on first use. */
31
+ const gatewayFor = async (prepared) => {
32
+ const gatewayed = daimonGatewayedEngines(prepared.engines);
33
+ if (gatewayed.length === 0)
34
+ return null;
35
+ const missing = gatewayed.filter((descriptor) => !logins.includes(descriptor.id));
36
+ if (missing.length > 0) {
37
+ throw new SpawnfileError("validation_error", `Auth profile ${options.authProfile.name} has no ${missing.map(({ id }) => id).join(", ")} login; run \`spawnfile auth import <engine> --profile ${options.authProfile.name}\``);
38
+ }
39
+ gateway ??= (async () => {
40
+ const image = `spawnfile-training-gateway:${runId.replace(/[^A-Za-z0-9_.-]/gu, "-").slice(0, 100)}`;
41
+ await docker(["tag", prepared.image, image]);
42
+ return { image, gateway: await startTrainingGateway({ authProfile: options.authProfile, docker, engines: logins,
43
+ image, runId, runtimeRoot: prepared.runtimeRoot }) };
44
+ })();
45
+ return (await gateway).gateway;
46
+ };
47
+ /**
48
+ * The volume-held login (`spawnfile auth login`) this organization mounts,
49
+ * as a profile view that carries nothing else: no env, no imports.
50
+ */
51
+ const realmFor = (prepared) => {
52
+ const engine = prepared.engines.find((id) => getDaimonEngineDescriptor(id)?.auth.staging === "secret-service");
53
+ if (engine === undefined)
54
+ return undefined;
55
+ const binding = options.authProfile.realms?.[engine];
56
+ // A login recorded before its home login files were kept cannot enroll a fresh home.
57
+ if (!binding || (HOME_LOGIN_FILES[engine] !== undefined && binding.homeVolume === undefined)) {
58
+ throw new SpawnfileError("validation_error", `Auth profile ${options.authProfile.name} has no ${engine} login; run \`spawnfile auth login ${engine} --profile ${options.authProfile.name}\``);
59
+ }
60
+ return { volume: binding.realmVolume, profile: { ...options.authProfile, env: {}, imports: {}, realms: { [engine]: binding } } };
61
+ };
62
+ /** Boots one container, holding its login realm's turn (if any) until the container is gone. */
63
+ const bootContainer = async (prepared, turn = {}) => {
64
+ const access = await gatewayFor(prepared);
65
+ const realm = realmFor(prepared);
66
+ const release = realm ? await turns.take(realm.volume, turn) : undefined;
67
+ try {
68
+ const booted = await prepared.boot(access, realm ? { realms: realm.profile } : {});
69
+ return { ...booted, teardown: async () => { try {
70
+ await booted.teardown();
71
+ }
72
+ finally {
73
+ release?.();
74
+ } } };
75
+ }
76
+ catch (error) {
77
+ release?.();
78
+ throw error;
79
+ }
80
+ };
81
+ const start = async (prepared, signal) => {
82
+ try {
83
+ const booted = await bootContainer(prepared, signal ? { signal } : {});
84
+ return { ...booted, teardown: async () => { try {
85
+ await booted.teardown();
86
+ }
87
+ finally {
88
+ await prepared.dispose();
89
+ } } };
90
+ }
91
+ catch (error) {
92
+ await prepared.dispose();
93
+ throw error;
94
+ }
95
+ };
96
+ /**
97
+ * A judge on a volume-held login takes turns with the run's trials: it stays
98
+ * warm while nobody else waits for the realm, and hands the turn over (its
99
+ * container removed) after its current judgment once someone does. Its image
100
+ * is built once and kept.
101
+ */
102
+ const takeTurnsJudge = (prepared) => {
103
+ let booted;
104
+ let container = "";
105
+ let busy = 0;
106
+ let evict = false;
107
+ const down = async () => {
108
+ const current = booted;
109
+ booted = undefined;
110
+ evict = false;
111
+ await (await current?.catch(() => undefined))?.teardown();
112
+ };
113
+ const timeoutMs = options.judgeRealmWaitMs ?? 30 * 60_000;
114
+ return {
115
+ get container() { return container; },
116
+ scanCredentials: async () => (await booted?.catch(() => undefined))?.scanCredentials() ?? [],
117
+ wake: async (text, wakeOptions) => {
118
+ busy++;
119
+ try {
120
+ if (!booted) {
121
+ const pending = bootContainer(prepared, { timeoutMs, ...(wakeOptions.signal ? { signal: wakeOptions.signal } : {}),
122
+ onContended: () => { evict = true; if (busy === 0)
123
+ void down(); } });
124
+ booted = pending;
125
+ pending.then((judge) => { container = judge.container; }, () => { if (booted === pending)
126
+ booted = undefined; });
31
127
  }
32
- finally {
33
- await prepared.dispose();
34
- } } };
128
+ return await (await booted).wake(text, wakeOptions);
129
+ }
130
+ finally {
131
+ busy--;
132
+ if (evict && busy === 0)
133
+ await down();
134
+ }
135
+ },
136
+ teardown: async () => { try {
137
+ await down();
35
138
  }
36
- catch (error) {
139
+ finally {
37
140
  await prepared.dispose();
38
- throw error;
141
+ } }
142
+ };
143
+ };
144
+ const directory = async (prefix) => {
145
+ await mkdir(options.scratchRoot, { recursive: true });
146
+ return mkdtemp(path.join(options.scratchRoot, prefix));
147
+ };
148
+ return {
149
+ boot: async ({ trialId, instructions, signal }) => start(await prepare({
150
+ agentManifestPath: options.agentManifestPath, docker, instructions, trialId, directory: await directory("trial-")
151
+ }), signal),
152
+ judge: (spec) => {
153
+ if (closed)
154
+ return Promise.reject(new SpawnfileError("runtime_error", "the training run is closed"));
155
+ const key = JSON.stringify([spec.engine, spec.model, spec.effort ?? null]);
156
+ let judge = judges.get(key);
157
+ if (!judge) {
158
+ judge = (async () => {
159
+ const root = await directory("judge-");
160
+ const prepared = await prepare({
161
+ agentManifestPath: await writeJudgeAgent(spec, path.join(root, "source")), docker, instructions: JUDGE_INSTRUCTIONS,
162
+ trialId: `judge-${spec.engine}-${key}-${runId}`, directory: root
163
+ });
164
+ let turnTaking;
165
+ try {
166
+ turnTaking = realmFor(prepared) !== undefined;
167
+ }
168
+ catch (error) {
169
+ await prepared.dispose();
170
+ throw error;
171
+ }
172
+ return turnTaking ? takeTurnsJudge(prepared) : start(prepared);
173
+ })();
174
+ judges.set(key, judge);
175
+ // A failed boot is not cached: the next judgment retries it.
176
+ judge.catch(() => { if (judges.get(key) === judge)
177
+ judges.delete(key); });
39
178
  }
179
+ return judge;
40
180
  },
41
181
  close: async () => {
182
+ closed = true;
183
+ const booted = await Promise.all([...judges.values()].map((judge) => judge.catch(() => undefined)));
184
+ judges.clear();
185
+ await Promise.all(booted.map((judge) => judge?.teardown().catch(() => undefined)));
42
186
  const started = await gateway?.catch(() => undefined);
43
187
  if (!started)
44
188
  return;
@@ -0,0 +1,35 @@
1
+ import { type ResolvedAuthProfile, type SubscriptionRealmBinding } from "../../../auth/index.js";
2
+ import { prepareTrial } from "./boot.js";
3
+ import { type TrialDocker } from "./docker.js";
4
+ export interface SubscriptionRealmLoginOptions {
5
+ profileName: string;
6
+ engine: string;
7
+ /** Prepare volumes and image and return the login command without running it or recording the login. */
8
+ dryRun?: boolean;
9
+ docker?: TrialDocker;
10
+ /** Where the throwaway login organization is compiled (default: a fresh temp directory). */
11
+ scratchRoot?: string;
12
+ /** Builds the throwaway one-agent organization the login runs in (tests only). */
13
+ prepare?: typeof prepareTrial;
14
+ }
15
+ export interface SubscriptionRealmLoginResult {
16
+ binding: SubscriptionRealmBinding;
17
+ /** The exact `docker run` argv the login uses. */
18
+ command: readonly string[];
19
+ profile: ResolvedAuthProfile;
20
+ }
21
+ /** The profile's volume names for an engine's volume-held login. */
22
+ export declare const subscriptionRealmBinding: (profileName: string, engine: string) => Required<SubscriptionRealmBinding>;
23
+ export declare const ensureSubscriptionRealmVolumes: (docker: TrialDocker, image: string, engine: string, binding: SubscriptionRealmBinding) => Promise<void>;
24
+ /**
25
+ * `spawnfile auth login <engine>`: gives an auth profile its own volume-held
26
+ * login for an engine that keeps its login in a Daimon secret-service realm
27
+ * (AGY). Creates the profile's realm, unlock and home login volumes, then runs
28
+ * Daimon's own interactive `auth <engine> login` in a throwaway,
29
+ * production-booted one-agent organization (a tool-free judge) attached to the
30
+ * operator's terminal, keeps the engine's login files from that throwaway home
31
+ * in the home login volume, and records the volume names on the profile once
32
+ * it succeeds.
33
+ * Spawnfile never reads the login or the unlock secret.
34
+ */
35
+ export declare const loginSubscriptionRealm: (options: SubscriptionRealmLoginOptions) => Promise<SubscriptionRealmLoginResult>;
@@ -0,0 +1,85 @@
1
+ import { mkdir, mkdtemp, rm } from "node:fs/promises";
2
+ import os from "node:os";
3
+ import path from "node:path";
4
+ import { ensureAuthProfile, registerSubscriptionRealm } from "../../../auth/index.js";
5
+ import { getDaimonEngineDescriptor } from "../../../runtime/daimon/index.js";
6
+ import { DAIMON_ORGANIZATION_UID } from "../../../runtime/daimon/runtimeIdentity.js";
7
+ import { DAIMON_PROFILE_UNLOCK_FILE } from "../../../runtime/daimon/subscriptionRealms.js";
8
+ import { SpawnfileError } from "../../../shared/index.js";
9
+ import { slugify } from "../../helpers.js";
10
+ import { prepareTrial } from "./boot.js";
11
+ import { createTrialDocker } from "./docker.js";
12
+ import { trainingGatewayRealmVolume } from "./gateway.js";
13
+ import { JUDGE_INSTRUCTIONS, writeJudgeAgent } from "./judge.js";
14
+ const LABEL = "spawnfile.subscription-realm";
15
+ /** The profile's volume names for an engine's volume-held login. */
16
+ export const subscriptionRealmBinding = (profileName, engine) => {
17
+ const prefix = `spawnfile-training-${slugify(profileName) || "profile"}-${engine}`;
18
+ return { homeVolume: `${prefix}-home`, realmVolume: trainingGatewayRealmVolume(profileName, engine), unlockVolume: `${prefix}-unlock` };
19
+ };
20
+ /**
21
+ * Creates the unlock secret inside its volume exactly once, as the organization
22
+ * uid Daimon checks it against (one `0600` regular file, no newline). Generated
23
+ * and written inside a network-less container: the bytes never reach the host.
24
+ * An existing secret is kept (replacing it would orphan the encrypted keyring)
25
+ * unless it is unsafe, which is refused.
26
+ */
27
+ const UNLOCK_PROGRAM = [
28
+ "const fs = require('node:fs'), crypto = require('node:crypto');",
29
+ "const [uid, name] = process.argv.slice(1); const target = `/unlock/${name}`;",
30
+ "try { const entry = fs.lstatSync(target);",
31
+ " if (!entry.isFile() || entry.nlink !== 1 || entry.uid !== Number(uid) || (entry.mode & 0o777) !== 0o600 || entry.size < 1) { console.error('existing unlock secret is unsafe'); process.exit(3); }",
32
+ " process.exit(0);",
33
+ "} catch (error) { if (error.code !== 'ENOENT') throw error; }",
34
+ "const fd = fs.openSync(target, fs.constants.O_WRONLY | fs.constants.O_CREAT | fs.constants.O_EXCL | fs.constants.O_NOFOLLOW, 0o600);",
35
+ "const bytes = Buffer.from(crypto.randomBytes(32).toString('hex'));",
36
+ "fs.writeSync(fd, bytes); bytes.fill(0); fs.fchmodSync(fd, 0o600); fs.fsyncSync(fd); fs.fchownSync(fd, Number(uid), Number(uid)); fs.closeSync(fd);"
37
+ ].join("\n");
38
+ export const ensureSubscriptionRealmVolumes = async (docker, image, engine, binding) => {
39
+ for (const volume of [binding.realmVolume, binding.unlockVolume, ...(binding.homeVolume ? [binding.homeVolume] : [])]) {
40
+ await docker(["volume", "create", "--label", `${LABEL}=${engine}`, volume]);
41
+ }
42
+ await docker(["run", "--rm", "--network", "none", "--user", "0:0", "--cap-drop", "ALL", "--cap-add", "CHOWN",
43
+ "--security-opt", "no-new-privileges", "--entrypoint", "node", "--mount", `type=volume,source=${binding.unlockVolume},target=/unlock`,
44
+ image, "-e", UNLOCK_PROGRAM, String(DAIMON_ORGANIZATION_UID), DAIMON_PROFILE_UNLOCK_FILE]);
45
+ };
46
+ /**
47
+ * `spawnfile auth login <engine>`: gives an auth profile its own volume-held
48
+ * login for an engine that keeps its login in a Daimon secret-service realm
49
+ * (AGY). Creates the profile's realm, unlock and home login volumes, then runs
50
+ * Daimon's own interactive `auth <engine> login` in a throwaway,
51
+ * production-booted one-agent organization (a tool-free judge) attached to the
52
+ * operator's terminal, keeps the engine's login files from that throwaway home
53
+ * in the home login volume, and records the volume names on the profile once
54
+ * it succeeds.
55
+ * Spawnfile never reads the login or the unlock secret.
56
+ */
57
+ export const loginSubscriptionRealm = async (options) => {
58
+ const descriptor = getDaimonEngineDescriptor(options.engine);
59
+ if (descriptor?.auth.staging !== "secret-service") {
60
+ throw new SpawnfileError("validation_error", `Engine ${options.engine} has no volume-held login; use \`spawnfile auth import ${options.engine}\``);
61
+ }
62
+ const docker = options.docker ?? createTrialDocker();
63
+ const current = await ensureAuthProfile(options.profileName);
64
+ // An earlier login keeps its volumes; one recorded before home login files were kept gains its home volume.
65
+ const binding = { ...subscriptionRealmBinding(current.name, options.engine), ...current.realms?.[options.engine] };
66
+ const realms = { ...current, env: {}, imports: {}, realms: { [options.engine]: binding } };
67
+ const scratch = options.scratchRoot ?? os.tmpdir();
68
+ await mkdir(scratch, { recursive: true });
69
+ const root = await mkdtemp(path.join(scratch, "spawnfile-auth-login-"));
70
+ let prepared;
71
+ try {
72
+ prepared = await (options.prepare ?? prepareTrial)({
73
+ agentManifestPath: await writeJudgeAgent({ engine: options.engine, model: "default" }, path.join(root, "source")),
74
+ directory: root, docker, instructions: JUDGE_INSTRUCTIONS, trialId: `login-${options.engine}-${current.name}`
75
+ });
76
+ await ensureSubscriptionRealmVolumes(docker, prepared.image, options.engine, binding);
77
+ const command = await prepared.login(realms, { dryRun: options.dryRun === true });
78
+ const profile = options.dryRun ? current : await registerSubscriptionRealm(current.name, options.engine, binding);
79
+ return { binding, command, profile };
80
+ }
81
+ finally {
82
+ await prepared?.dispose();
83
+ await rm(root, { recursive: true, force: true });
84
+ }
85
+ };
@@ -0,0 +1,20 @@
1
+ /** Gives the turn back; idempotent. */
2
+ export type ReleaseRealmTurn = () => void;
3
+ export interface RealmTurnOptions {
4
+ /** Called once on the holder when another caller starts waiting: a warm holder should hand the turn over. */
5
+ onContended?: () => void;
6
+ /** Bound on the wait; on expiry the caller is refused instead of waiting forever. */
7
+ timeoutMs?: number;
8
+ signal?: AbortSignal;
9
+ }
10
+ /**
11
+ * First-come turns on exclusive login realms, one holder per realm at a time.
12
+ * An engine whose login is one realm held under an exclusive lock (Daimon's
13
+ * AGY keyring, `flock` on `.daimon-lease`) admits one container per login:
14
+ * every container of a run that mounts that realm takes a turn here first, so
15
+ * a second container never boots into the lock and dies at readiness.
16
+ */
17
+ export interface RealmTurns {
18
+ take(realm: string, options?: RealmTurnOptions): Promise<ReleaseRealmTurn>;
19
+ }
20
+ export declare const createRealmTurns: () => RealmTurns;
@@ -0,0 +1,69 @@
1
+ import { SpawnfileError } from "../../../shared/index.js";
2
+ export const createRealmTurns = () => {
3
+ const realms = new Map();
4
+ const release = (key, state) => {
5
+ let released = false;
6
+ return () => {
7
+ if (released)
8
+ return;
9
+ released = true;
10
+ const next = state.queue.shift();
11
+ if (!next) {
12
+ realms.delete(key);
13
+ return;
14
+ }
15
+ state.holder = next.options;
16
+ state.contended = false;
17
+ next.grant();
18
+ if (state.queue.length > 0)
19
+ notify(state);
20
+ };
21
+ };
22
+ const notify = (state) => {
23
+ if (state.contended)
24
+ return;
25
+ state.contended = true;
26
+ state.holder?.onContended?.();
27
+ };
28
+ return {
29
+ take: (key, options = {}) => {
30
+ if (options.signal?.aborted)
31
+ return Promise.reject(new SpawnfileError("runtime_error", `cancelled waiting for login realm ${key}`));
32
+ const state = realms.get(key);
33
+ if (!state) {
34
+ const fresh = { holder: options, contended: false, queue: [] };
35
+ realms.set(key, fresh);
36
+ return Promise.resolve(release(key, fresh));
37
+ }
38
+ return new Promise((resolve, reject) => {
39
+ let timer;
40
+ const leave = (message) => {
41
+ const index = state.queue.indexOf(waiter);
42
+ if (index < 0)
43
+ return;
44
+ state.queue.splice(index, 1);
45
+ if (timer)
46
+ clearTimeout(timer);
47
+ options.signal?.removeEventListener("abort", onAbort);
48
+ reject(new SpawnfileError("runtime_error", message));
49
+ };
50
+ const onAbort = () => leave(`cancelled waiting for login realm ${key}`);
51
+ const waiter = {
52
+ options,
53
+ grant: () => {
54
+ if (timer)
55
+ clearTimeout(timer);
56
+ options.signal?.removeEventListener("abort", onAbort);
57
+ resolve(release(key, state));
58
+ }
59
+ };
60
+ state.queue.push(waiter);
61
+ if (options.timeoutMs !== undefined) {
62
+ timer = setTimeout(() => leave(`login realm ${key} stayed held by another container for ${options.timeoutMs}ms; one login admits one container at a time`), options.timeoutMs);
63
+ }
64
+ options.signal?.addEventListener("abort", onAbort, { once: true });
65
+ notify(state);
66
+ });
67
+ }
68
+ };
69
+ };
@@ -31,7 +31,8 @@ const orderModelTarget = (target) => {
31
31
  ["provider", target.provider],
32
32
  ["name", target.name],
33
33
  ["auth", orderModelEntryAuth(target.auth)],
34
- ["endpoint", target.endpoint]
34
+ ["endpoint", target.endpoint],
35
+ ["reasoning_effort", target.reasoning_effort]
35
36
  ]);
36
37
  };
37
38
  const orderExecution = (execution) => {
@@ -2,7 +2,7 @@ import path from "node:path";
2
2
  import { CLI_ENGINE_SKILL_BASE_DIRECTORIES } from "../common.js";
3
3
  import { daimonGrokSkillsError } from "./grokSkillsSupport.js";
4
4
  import { daimonAgentSkillsFromResolved } from "./grokWorkerSkills.js";
5
- import { daimonGatewayedSubscriptionRealms } from "./subscriptionRealms.js";
5
+ import { daimonGatewayedSubscriptionRealms, daimonSubscriptionRealmMountId } from "./subscriptionRealms.js";
6
6
  import { parseEveryScheduleMs } from "../scheduleUtils.js";
7
7
  import { SpawnfileError } from "../../shared/index.js";
8
8
  import { DAIMON_AGY_SUBSCRIPTION_REALM, DAIMON_GROK_TURN_USAGE_LEDGER } from "./contractManifest.js";
@@ -32,7 +32,7 @@ export const DAIMON_RUNTIME_HOMES_DIRECTORY = "runtime-homes";
32
32
  const DAIMON_MAX_CONFIG_BYTES = 1_048_576;
33
33
  const DAIMON_MAX_INSTRUCTION_BYTES = 16_384;
34
34
  const DAIMON_MAX_INSTRUCTION_CODEPOINTS = 16_384;
35
- import { DAIMON_ENGINES, DAIMON_DEFAULT_ENGINE, getDaimonEngineDescriptor, daimonEngineHasBroker } from "./engines.js";
35
+ import { DAIMON_ENGINES, DAIMON_DEFAULT_ENGINE, DAIMON_SECRET_SERVICE_ENGINE_ID, getDaimonEngineDescriptor, daimonEngineHasBroker } from "./engines.js";
36
36
  export { DAIMON_ENGINES } from "./engines.js";
37
37
  const normalizeSchedule = (node) => {
38
38
  const schedule = node.schedule;
@@ -315,7 +315,7 @@ export const createDaimonContainerTargets = async (inputs) => {
315
315
  mountPath: DAIMON_GROK_TURN_USAGE_LEDGER.directoryPath,
316
316
  reason: "Daimon per-turn engine usage ledger"
317
317
  }, ...(hasAgy ? [{
318
- id: "daimon-agy-subscription-realm",
318
+ id: daimonSubscriptionRealmMountId(DAIMON_SECRET_SERVICE_ENGINE_ID),
319
319
  // The AGY subscription credential is an OS-keyring entry created by an
320
320
  // interactive browser OAuth that has no headless equivalent; it lives
321
321
  // in this volume. Without this lifecycle the volume name folds in the
@@ -1,4 +1,4 @@
1
- export declare const DAIMON_ENGINE_DESCRIPTOR_SOURCE_COMMIT: "a42a2b23722eadc44874e8caf117d17237e1095f";
1
+ export declare const DAIMON_ENGINE_DESCRIPTOR_SOURCE_COMMIT: "c5337565df0b60151ae731b17878f784c13a9337";
2
2
  export declare const DAIMON_V5_ENGINE_DESCRIPTORS: {
3
3
  readonly agy: {
4
4
  readonly auth: {
@@ -1,4 +1,4 @@
1
1
  /* v8 ignore file -- generated data module */
2
2
  // Generated by scripts/generate-daimon-engine-descriptors.ts from pinned Daimon static descriptors. Do not edit.
3
- export const DAIMON_ENGINE_DESCRIPTOR_SOURCE_COMMIT = "a42a2b23722eadc44874e8caf117d17237e1095f";
3
+ export const DAIMON_ENGINE_DESCRIPTOR_SOURCE_COMMIT = "c5337565df0b60151ae731b17878f784c13a9337";
4
4
  export const DAIMON_V5_ENGINE_DESCRIPTORS = { "agy": { "auth": { "busEnvironment": "DBUS_SESSION_BUS_ADDRESS", "format": null, "method": null, "provider": null, "realm": { "directoryMode": 448, "durableMountPath": "/var/lib/spawnfile/daimon/agy-subscription-realm", "fileMode": 384, "maxUnlockBytes": 4096, "unlockMountPath": "/var/lib/spawnfile/daimon/agy-unlock-secret", "unlockSourceSlot": "agy-unlock-secret" }, "staging": "secret-service" }, "authKinds": ["subscription"], "broker": null, "capabilities": { "broker": false, "nativeSandbox": false, "portableCredential": false, "secretService": true }, "credentialMaterial": null, "homeDirectory": "", "homeEnvironment": "ANTIGRAVITY_CLI_HOME", "id": "agy", "modelSelection": { "configurable": false, "declarationRequiresBroker": false, "defaults": { "model": null, "reasoningEffort": null }, "models": null, "reasoningEfforts": [], "requiresPairedDeclaration": false }, "requiredBinaries": ["agy", "dbus-daemon", "gnome-keyring-daemon"], "sandbox": { "configurable": false }, "training": { "inferenceGrants": null, "subject": { "isolation": null, "reason": "no verified per-agent sandbox", "supported": false } } }, "codex": { "auth": { "directoryMode": 448, "fileMode": 384, "fileName": "auth.json", "format": { "accessTokenKeys": ["access_token", "accessToken", "token"], "containerKey": "tokens", "fallbackToRoot": true, "refreshTokenKeys": ["refresh_token", "refreshToken"] }, "maxCredentialBytes": 65536, "method": "codex", "provider": "openai", "realm": { "agentCredentialRelativePath": ".codex/auth.json", "bootstrapMountPath": "/var/lib/spawnfile/daimon/codex-bootstrap-auth", "bootstrapSourceSlot": "codex-auth", "directoryMode": 448, "durableMountPath": "/var/lib/spawnfile/daimon/codex-subscription-realm", "fileMode": 384, "maxCredentialBytes": 65536 }, "staging": "portable-realm" }, "authKinds": ["subscription"], "broker": null, "capabilities": { "broker": false, "nativeSandbox": true, "portableCredential": true, "secretService": false }, "credentialMaterial": { "destinationRelativePath": ".codex/auth.json", "directoryMode": 448, "fileMode": 384, "sourceRelativePath": ".daimon-inbound/codex-auth", "sourceSlot": "codex-auth" }, "homeDirectory": ".codex", "homeEnvironment": "CODEX_HOME", "id": "codex", "modelSelection": { "configurable": true, "declarationRequiresBroker": false, "defaults": { "model": null, "reasoningEffort": null }, "models": { "kind": "non-empty-string" }, "reasoningEfforts": ["none", "minimal", "low", "medium", "high", "xhigh", "max", "ultra", "persistent"], "requiresPairedDeclaration": false }, "piAuthMethod": "codex", "piProvider": "openai-codex", "piSourceProvider": "openai", "requiredBinaries": ["codex"], "sandbox": { "configurable": true, "policy": { "mode": "workspace-write", "networkAccess": false, "webSearch": "disabled" } }, "training": { "inferenceGrants": null, "subject": { "isolation": "native-sandbox", "supported": true } } }, "grok": { "auth": { "directoryMode": 448, "fileMode": 384, "fileName": "auth.json", "format": { "accessTokenKeys": ["key"], "entryKeyPattern": "^https://auth\\.x\\.ai::", "expiresAtKey": "expires_at", "refreshTokenKeys": ["refresh_token"] }, "maxCredentialBytes": 65536, "method": "grok", "provider": "xai", "realm": { "agentCredentialRelativePath": ".grok/auth.json", "bootstrapMountPath": "/var/lib/spawnfile/daimon/grok-bootstrap-auth", "bootstrapSourceSlot": "grok-auth", "directoryMode": 448, "durableMountPath": "/var/lib/spawnfile/daimon/grok-subscription-realm", "fileMode": 384, "maxCredentialBytes": 65536 }, "staging": "broker-realm" }, "authKinds": ["subscription"], "broker": { "artifacts": { "arm64Sha256": "d0dc1c03197c3e90f09b66ad7c89b4f7b448d06dc84c03b247dce976d6018d6e", "sourceSha256": "15836d7ad69f12ef581a6e5b8635c9db43b2177dac609160c0749d3d1fefbaa8", "x64Sha256": "95aa9c272225e74ff9f45f54dde4bc30aee324e9ba24d8a876db9151c81b454d" }, "backendSocketPath": "/run/daimon-engine-broker/backend.sock", "bounds": { "capabilityBundleBytes": 8196, "capabilityBytes": 4096, "outputBytes": 262144, "promptBytes": 65536 }, "controlProtocolVersion": "noopolis.daimon.engine-broker.v4", "controlSocketPath": "/run/daimon-engine-broker/control.sock", "credentialHomePath": "/var/lib/spawnfile/daimon/grok-subscription-realm", "grokCliArtifacts": { "arm64": { "bytes": 136090504, "sha256": "39ab87666877d64ef3a40aa60fbe0c3b6a6acd7001b78fe60e2c76bb6cfc4a94", "url": "https://storage.googleapis.com/grok-build-public-artifacts/cli/grok-1.0.34-linux-aarch64" }, "x64": { "bytes": 163035648, "sha256": "be5905e107d2b8b5f3c142d21ecfe4c8fd32a913d2fd551b788707930c4dc80d", "url": "https://storage.googleapis.com/grok-build-public-artifacts/cli/grok-1.0.34-linux-x86_64" } }, "grokCliBuild": "3736acbc8658", "grokCliVersion": "1.0.34", "grokExecutablePath": "/usr/local/bin/grok", "identities": { "brokerUid": 2100, "firstWorkerUid": 2200, "organizationUid": 2000 }, "inferenceGrants": { "bodyMembers": ["messages", "model", "reasoning_effort", "response_format", "stream", "stream_options"], "client": { "configSha256": { "grok-4.5": { "high": "ffbc33728b821e9854fbc7c93601e599225da421ecfd6ebf10d314afcc28d6f2", "low": "a07f7436f1268bb399ec233c65d3b3d8fb99a11a1f175f8da1ca133c9367bc74", "medium": "1f4c0d4dad1f3b09419b5739db6423a09e0049abc091594c64123a75dd53dfb9" }, "grok-4.6": { "high": "5652656effa82f0c4f09cf8226b16e6140332a5a358b571194bb5563312367ac", "low": "79314d039f787e4ebfec7dacf57adc969086b948f564dec008f0ed6367e6062f", "medium": "6f538de0547c0c4e6a3f04ae08595ceadadabb06b75f6b6ee4c428744bb95cd8" }, "grok-build": { "high": "98d16f2b7d12f4eb540d625c853e51d227933e204923e43e8b9b4176f10aca2c", "low": "ca15c6a562a008227d39c51d3a3a83715663089b3784e8b46debb1fb67b3c4a1", "medium": "01783fb6beadcf6f8486fff0836820ad43fab5662b812a907fe9cfdb83e9804d" } }, "envKey": "DAIMON_INFERENCE_GRANT", "modelId": "daimon-inference-grok" }, "failureCodes": ["auth_stale", "grant_limit", "invalid_request", "unavailable"], "ledgerDedupeKey": ["grant", "request"], "ledgerVersion": "noopolis.daimon.inference-usage.v1", "limits": { "maxRequests": 64, "maxTokens": 2000000 }, "maxInFlightRequestsPerGrant": 1, "maxLiveGrants": 8, "messageRoles": ["system", "user", "assistant"], "purposes": ["judge", "optimizer"], "requestKinds": ["request_inference_grant", "release_inference_grant"], "tokenPrefix": "inference_", "ttlMs": 600000 }, "launcherSocketPath": "/run/daimon-engine-broker/launcher.sock", "mcpFacade": { "host": "127.0.0.1", "path": "/mcp", "port": 43124 }, "nativeAbiVersion": 2, "nativeExecutablePath": "/opt/daimon/bin/daimon-engine-broker", "projectionVersion": "noopolis.daimon.grok-broker-projection.v3", "providerProxy": { "host": "127.0.0.1", "port": 43123 }, "registrationPath": "/etc/daimon-engine-broker/registrations.bin", "runRequestBudget": { "countsCredentialRetries": true, "fileName": "run-requests.json", "includesInferenceGrants": true, "maximumField": "maxRunRequests", "storeField": "runRequestStore" }, "serviceConfigPath": "/etc/daimon-engine-broker/service.json", "serviceConfigVersions": ["noopolis.daimon.engine-broker-service.v1", "noopolis.daimon.engine-broker-service.v2", "noopolis.daimon.engine-broker-service.v3"], "slotPreflightVersion": "noopolis.daimon.grok-slot-preflight.v2", "slotRouting": { "controlCaller": "organization", "key": "slot", "repeatedAgentIds": true, "resetRequest": "reset_slot", "resetResponse": "slot_reset", "slotEnvironment": "DAIMON_ENGINE_BROKER_SLOT", "turnStoreDirectory": "slot-{slot}", "workersMayControl": false }, "turnLimits": { "bounds": { "maxRequests": [1, 48], "maxTokens": [1, 10000000], "timeoutMs": [1000, 3600000] }, "keys": ["maxRequests", "maxTokens", "timeoutMs"], "limitReasons": ["tokens", "requests", "timeout", "none"], "maxInFlightRequests": 1, "missingUsageEstimate": { "inputBytesPerToken": 2, "outputTokens": 4096 }, "requestUsageMaxTokens": 500000, "tokenCeilingOvershoot": "at-most-one-request", "v1Defaults": { "maxRequests": 32, "maxTokens": 300000, "timeoutMs": 240000 }, "wakeMayOnlyLower": true }, "turnRecordVersions": ["noopolis.daimon.engine-broker-turn.v1", "noopolis.daimon.engine-broker-turn.v2"], "turnStorePath": "/var/lib/spawnfile/daimon/grok-subscription-realm/turns", "wakeLimitEnvironment": { "maxTokens": "DAIMON_ENGINE_WAKE_TOKEN_CEILING", "timeoutMs": "DAIMON_ENGINE_WAKE_TIMEOUT_MS" }, "worker": { "clockedConfigSha256": { "grok-4.5": { "high": "907d8967960c342b442d6d256b2585f3c85bd846a78578f596f0b605403d6d34", "low": "3c4f3515b21c1bffb3fb770e2ecb4b918b6c43d5e77c1fd47e1e6698d1fedee7", "medium": "9117e12b2f3f6fa045799592969cbaae1c2f3b1ea79330badac8655b9b41dd7a" }, "grok-4.6": { "high": "203744f6f0dfc0bc80cfb896880497edfd9b3de4dcf33060e8ef4d2ef5f220a7", "low": "751f1dcd04983e5e5883df5a8fefa04f201e187e5ef1f344d3bf83f950830432", "medium": "f1406f93a8091eb0c09e07321254a9c783a89b0bbf5548d9613d53a8d087a517" }, "grok-build": { "high": "6efddadc82c38020d3351829e54bb09fa456cd6d76ea1247902794d82a4a3ffa", "low": "a8c63ba910623a0686930c27db0733f4a2588c7fca9dd7da25c3f18027720ab5", "medium": "6afcd2b90c0d19794f8c0d22147a0f011946a92e613f89dae98b0ca729313101" } }, "configSha256": { "grok-4.5": { "high": "c63c3387ce92d94ec3f690abfe98942afcd7c9e17ff84816bbe751f340ab251f", "low": "8247127c3625ff7c5d8d527a53596b89ec6557a821ac46cfd00bd122b90daff6", "medium": "59288cee61297bb8c002097061a48f77b09d310754187a253ee089f7172a9155" }, "grok-4.6": { "high": "65b0212564fb74042b1503d293fb8d3620276033264c0efade2a539ca09218e3", "low": "ab58499ac32678097c146479896f2b8a8e2b0e39aea22dc0a60b6227e370538e", "medium": "df1a5cc84346e7f6bf6090492fbd19faaefb42953e3bb2e8c6cbc0572242403f" }, "grok-build": { "high": "a23724e00d670caee185ba7690d2daa868173e53905cf446f5329666f01ab4e3", "low": "fb343f2809903f26d21681470943235031f946e99085542fd89555eb7782cbb5", "medium": "8a587ef75c90eab70d19b24583e60051d6fba9d90c558839fdbb15588b4cc656" } }, "defaultModel": "grok-4.6", "defaultReasoningEffort": "low", "home": { "directory": { "group": "worker", "mode": 1017, "uid": 0 }, "organizationRuntimeHome": { "group": "worker", "mode": 456, "owner": "organization" }, "privateTmp": { "mode": 448, "owner": "worker", "relativeToWorkerHome": "tmp" }, "readOnlyFiles": { "gid": 0, "mode": 292, "names": ["config.toml", "managed_config.toml", "requirements.toml", "sandbox.toml", "trusted_folders.toml"], "uid": 0 }, "sandboxEvents": { "group": "broker", "mode": 416, "owner": "worker", "relativePath": "sessions/sandbox-events.jsonl" }, "sessionsDirectory": { "group": "worker", "mode": 1017, "relativePath": "sessions", "uid": 0 }, "sharedTmp": { "maxGroupExclusive": 2200, "mode": 1020, "otherMode": 4, "paths": ["/tmp", "/var/tmp"], "uid": 0 }, "spillDirectory": { "fileMode": 416, "group": "worker", "mode": 1512, "owner": "organization", "relativeToRuntimeHome": "tool-output" } }, "maxTurns": 48, "modelId": "daimon-broker-grok", "models": ["grok-4.6", "grok-4.5", "grok-build"], "reasoningEfforts": ["low", "medium", "high"], "systemPromptSha256": "2c31c0085a54a4efbf9c0cf0b8124c56e47f38691b7f0c7fa233a74abaa8ddf8", "taskClock": { "directoryMode": 493, "directoryPath": "/run/daimon-engine-broker/task-clock/slot-0", "fileMode": 420, "ownerUid": 2100, "preloadPath": "/usr/local/lib/daimon/libfaketime.so.1", "rootDirectoryPath": "/run/daimon-engine-broker/task-clock", "slotDirectoryPattern": "/run/daimon-engine-broker/task-clock/slot-{slot}", "slotFilePattern": "/run/daimon-engine-broker/task-clock/slot-{slot}/faketime", "timestampFilePath": "/run/daimon-engine-broker/task-clock/slot-0/faketime", "version": "noopolis.daimon.grok-broker-task-clock.v2", "workerView": "own-directory-visible-sibling-directories-denied" }, "toolIds": ["run_terminal_cmd", "read_file", "grep", "list_dir", "search_tool", "use_tool"], "visibleTools": ["grep", "list_dir", "read_file", "run_terminal_command", "search_tool", "use_tool"] } }, "capabilities": { "broker": true, "nativeSandbox": true, "portableCredential": true, "secretService": false }, "credentialMaterial": { "destinationRelativePath": ".grok/auth.json" }, "homeDirectory": ".grok", "homeEnvironment": "GROK_HOME", "id": "grok", "modelSelection": { "configurable": true, "declarationRequiresBroker": true, "defaults": { "model": "grok-4.6", "reasoningEffort": "low" }, "models": { "kind": "enum", "values": ["grok-4.6", "grok-4.5", "grok-build"] }, "reasoningEfforts": ["low", "medium", "high"], "requiresPairedDeclaration": true }, "requiredBinaries": ["grok", "daimon-engine-broker"], "sandbox": { "baseProfile": "strict", "configurable": false, "denyPaths": { "canonicalAbsolute": true, "forbiddenCharacterPattern": "[\"\\\\\\u0000-\\u001f\\u007f*?[\\]]", "rootAllowed": false, "trailingSlashAllowed": false }, "profile": "daimon-strict", "restrictNetwork": true }, "training": { "inferenceGrants": { "bodyMembers": ["messages", "model", "reasoning_effort", "response_format", "stream", "stream_options"], "client": { "configSha256": { "grok-4.5": { "high": "ffbc33728b821e9854fbc7c93601e599225da421ecfd6ebf10d314afcc28d6f2", "low": "a07f7436f1268bb399ec233c65d3b3d8fb99a11a1f175f8da1ca133c9367bc74", "medium": "1f4c0d4dad1f3b09419b5739db6423a09e0049abc091594c64123a75dd53dfb9" }, "grok-4.6": { "high": "5652656effa82f0c4f09cf8226b16e6140332a5a358b571194bb5563312367ac", "low": "79314d039f787e4ebfec7dacf57adc969086b948f564dec008f0ed6367e6062f", "medium": "6f538de0547c0c4e6a3f04ae08595ceadadabb06b75f6b6ee4c428744bb95cd8" }, "grok-build": { "high": "98d16f2b7d12f4eb540d625c853e51d227933e204923e43e8b9b4176f10aca2c", "low": "ca15c6a562a008227d39c51d3a3a83715663089b3784e8b46debb1fb67b3c4a1", "medium": "01783fb6beadcf6f8486fff0836820ad43fab5662b812a907fe9cfdb83e9804d" } }, "envKey": "DAIMON_INFERENCE_GRANT", "modelId": "daimon-inference-grok" }, "failureCodes": ["auth_stale", "grant_limit", "invalid_request", "unavailable"], "ledgerDedupeKey": ["grant", "request"], "ledgerVersion": "noopolis.daimon.inference-usage.v1", "limits": { "maxRequests": 64, "maxTokens": 2000000 }, "maxInFlightRequestsPerGrant": 1, "maxLiveGrants": 8, "messageRoles": ["system", "user", "assistant"], "purposes": ["judge", "optimizer"], "requestKinds": ["request_inference_grant", "release_inference_grant"], "tokenPrefix": "inference_", "ttlMs": 600000 }, "subject": { "isolation": "broker-worker", "supported": true } } } };
@@ -3,4 +3,4 @@ export { DAIMON_PACKAGE_NAME } from './packageName.js';
3
3
  export * from './engines.js';
4
4
  export * from './contractManifestSchema.js';
5
5
  export { DAIMON_GATEWAY_KEY_ENV, DAIMON_GATEWAY_URL_ENV } from './gateway.js';
6
- export { isDaimonGatewayRealmMountId } from './subscriptionRealms.js';
6
+ export { daimonProfileRealmVolume, daimonSubscriptionRealmMountId, isDaimonGatewayRealmMountId } from './subscriptionRealms.js';
@@ -3,4 +3,4 @@ export { DAIMON_PACKAGE_NAME } from './packageName.js';
3
3
  export * from './engines.js';
4
4
  export * from './contractManifestSchema.js';
5
5
  export { DAIMON_GATEWAY_KEY_ENV, DAIMON_GATEWAY_URL_ENV } from './gateway.js';
6
- export { isDaimonGatewayRealmMountId } from './subscriptionRealms.js';
6
+ export { daimonProfileRealmVolume, daimonSubscriptionRealmMountId, isDaimonGatewayRealmMountId } from './subscriptionRealms.js';
@@ -7,6 +7,7 @@ import { SpawnfileError } from "../../shared/index.js";
7
7
  import { assertDaimonRuntimeHome, DAIMON_ORGANIZATION_RUNTIME_CONFIG_VERSIONS } from "./contractManifest.js";
8
8
  import { DAIMON_ENGINE_DESCRIPTORS, DAIMON_ENGINES, DAIMON_PORTABLE_ENGINE_ID, DAIMON_SECRET_SERVICE_ENGINE_ID, getDaimonEngineDescriptor } from "./engines.js";
9
9
  import { DAIMON_ORGANIZATION_UID } from "./runtimeIdentity.js";
10
+ import { daimonProfileUnlockMountArgs } from "./subscriptionRealms.js";
10
11
  const MAX_OPAQUE_CREDENTIAL_BYTES = 64 * 1024;
11
12
  export const DAIMON_GROK_ACCESS_TOKEN_MIN_BYTES = 32;
12
13
  export const DAIMON_GROK_REFRESH_TOKEN_MIN_BYTES = 16;
@@ -276,6 +277,13 @@ export const prepareDaimonRuntimeAuth = async (input) => {
276
277
  const descriptor = descriptorForEngine(engine);
277
278
  if (descriptor.auth.staging !== staging)
278
279
  continue;
280
+ const bound = descriptor.auth.staging === "secret-service" ? input.authProfile?.realms?.[engine] : undefined;
281
+ if (bound && descriptor.auth.staging === "secret-service") {
282
+ // The profile's own login (`spawnfile auth login`): its unlock secret lives in a
283
+ // volume Daimon checks in-container, so no host file and no host owner gate.
284
+ mountArgs.push(...daimonProfileUnlockMountArgs(bound.unlockVolume, descriptor.auth.realm.unlockMountPath));
285
+ continue;
286
+ }
279
287
  const source = daimonSourcePathForEngine(engine, process.env, input.authProfile);
280
288
  if (descriptor.auth.staging === "portable-realm") {
281
289
  const ownerUid = await assertSafeDaimonSourceFile(source, engine, descriptor.auth.maxCredentialBytes, engine);
@@ -1,3 +1,21 @@
1
+ import type { ResolvedAuthProfile } from "../../auth/index.js";
2
+ /**
3
+ * Realm resources for every gatewayed engine: one exclusive-reattach realm
4
+ * volume the auth gateway alone owns, and one opaque bootstrap leaf mounted
5
+ * under the gateway-private root. The volume id is the realm's identity, so a
6
+ * moved mount path still reattaches the same login.
7
+ */
8
+ export declare const daimonSubscriptionRealmMountId: (engine: string) => string;
9
+ /** The file inside a profile's unlock volume that is mounted as the realm unlock secret. */
10
+ export declare const DAIMON_PROFILE_UNLOCK_FILE = "unlock";
11
+ /**
12
+ * The volume a compiled realm mount reattaches when the selected auth profile
13
+ * holds that engine's login (`spawnfile auth login <engine>`): the profile's
14
+ * realm volume instead of the deployment-lineage one.
15
+ */
16
+ export declare const daimonProfileRealmVolume: (mountId: string, profile: Pick<ResolvedAuthProfile, "realms"> | null | undefined) => string | undefined;
17
+ /** The read-only mount of a profile's unlock secret at the engine's declared unlock path. */
18
+ export declare const daimonProfileUnlockMountArgs: (unlockVolume: string, unlockMountPath: string) => string[];
1
19
  /**
2
20
  * Whether a compiled persistent mount is a gatewayed realm. An organization
3
21
  * booted against an external gateway (`DAIMON_GATEWAY_URL` at boot) mounts
@@ -6,7 +6,20 @@ import { DAIMON_ENGINES } from "./engines.js";
6
6
  * under the gateway-private root. The volume id is the realm's identity, so a
7
7
  * moved mount path still reattaches the same login.
8
8
  */
9
- const realmMountId = (engine) => `daimon-${engine}-subscription-realm`;
9
+ export const daimonSubscriptionRealmMountId = (engine) => `daimon-${engine}-subscription-realm`;
10
+ const realmMountId = daimonSubscriptionRealmMountId;
11
+ /** The file inside a profile's unlock volume that is mounted as the realm unlock secret. */
12
+ export const DAIMON_PROFILE_UNLOCK_FILE = "unlock";
13
+ /**
14
+ * The volume a compiled realm mount reattaches when the selected auth profile
15
+ * holds that engine's login (`spawnfile auth login <engine>`): the profile's
16
+ * realm volume instead of the deployment-lineage one.
17
+ */
18
+ export const daimonProfileRealmVolume = (mountId, profile) => Object.entries(profile?.realms ?? {}).find(([engine]) => realmMountId(engine) === mountId)?.[1].realmVolume;
19
+ /** The read-only mount of a profile's unlock secret at the engine's declared unlock path. */
20
+ export const daimonProfileUnlockMountArgs = (unlockVolume, unlockMountPath) => [
21
+ "--mount", `type=volume,source=${unlockVolume},target=${unlockMountPath},volume-subpath=${DAIMON_PROFILE_UNLOCK_FILE},readonly`
22
+ ];
10
23
  /**
11
24
  * Whether a compiled persistent mount is a gatewayed realm. An organization
12
25
  * booted against an external gateway (`DAIMON_GATEWAY_URL` at boot) mounts
@@ -1,4 +1,4 @@
1
- import type { SubjectAdapter } from '../../../../training/index.js';
1
+ import type { SubjectAdapter, Usage } from '../../../../training/index.js';
2
2
  export declare const BOOTED_ADAPTER_ID = "daimon-booted";
3
3
  export declare const BOOTED_EVIDENCE_SCHEMA = "spawnfile.training.daimon-booted.wake.v1";
4
4
  /** One ledger row a wake appended (`noopolis.daimon.turn-usage.v1`), as far as Training reads it. */
@@ -17,6 +17,8 @@ export interface BootedWake {
17
17
  text: string;
18
18
  usage: readonly BootedUsageRow[];
19
19
  transcript: string | null;
20
+ /** Per model request, the tool-call names its response carried; null where the runtime could not say. */
21
+ requestToolCalls?: readonly (readonly string[] | null)[];
20
22
  }
21
23
  export interface BootedTrialHandle {
22
24
  wake(text: string, options: {
@@ -38,6 +40,8 @@ export interface BootedAdapterOptions {
38
40
  launcher: BootedTrialLauncher;
39
41
  timeoutMs: number;
40
42
  }
43
+ /** Ledger rows to `Usage`; no rows means unmetered, never zero. */
44
+ export declare const bootedUsage: (rows: readonly BootedUsageRow[]) => Usage | null;
41
45
  /**
42
46
  * A training trial as a production-booted organization: the container is the
43
47
  * isolation, the wake is the turn, and the evidence is what the runtime itself