mirror of
https://github.com/PR0M3TH3AN/TORCH.git
synced 2026-10-27 07:51:52 +00:00
feat: support platform and model info in nostr lock events
This change enables agents to report their execution platform (e.g., Jules, Codex, Goose) and model (e.g., DeepSeek 3.2) in the Nostr lock events. Key changes: - Updated `torch-lock` CLI to accept `--platform` and `--model` arguments. - Implemented `detectPlatform` utility to infer platform from environment variables if not provided. - Updated `src/lib.mjs` to include these fields in the event content. - Updated `scripts/agent/run-scheduler-cycle.mjs` to propagate `--model` and `AGENT_MODEL`. - Updated `dashboard/index.html` to display the model information on the lock card. - Fixed a regression in `scripts/validate-scheduler-flow-parity.mjs` and `test/scheduler-ratchet.test.mjs` caused by argument string matching. - Deleted `repro_test.mjs` temporary file. Co-authored-by: PR0M3TH3AN <[email protected]>
This commit is contained in:
1 parent
3156ee0bb5
commit
754a1c2ce1
9 files changed
+1481
-19
No files matched your search
@@ -437,6 +437,7 @@
|
||||
status: content.status ?? 'unknown',
|
||||
date: content.date ?? dTag.split('/')[3] ?? todayStr(),
|
||||
platform: content.platform ?? 'unknown',
|
||||
model: content.model ?? null,
|
||||
};
|
||||
}
|
||||
|
||||
@@ -585,8 +586,14 @@
|
||||
left.appendChild(meta);
|
||||
header.appendChild(left);
|
||||
|
||||
const right = createElement('div', 'flex flex-col items-end gap-1');
|
||||
const badge = createElement('span', `inline-flex items-center rounded-full px-2 py-0.5 text-xs font-medium ${ps.bg} ${ps.text}`, ps.label);
|
||||
header.appendChild(badge);
|
||||
right.appendChild(badge);
|
||||
|
||||
if (lock.model && lock.model !== 'unknown') {
|
||||
right.appendChild(createElement('span', 'text-xs text-muted mono opacity-75', lock.model));
|
||||
}
|
||||
header.appendChild(right);
|
||||
card.appendChild(header);
|
||||
|
||||
// Grid
|
||||
|
||||
@@ -143,6 +143,7 @@ a { color: inherit; }
|
||||
.w-full { width: 100%; }
|
||||
.shrink-0 { flex-shrink: 0; }
|
||||
.opacity-60 { opacity: 0.6; }
|
||||
.opacity-75 { opacity: 0.75; }
|
||||
|
||||
.text-center { text-align: center; }
|
||||
.text-xs { font-size: 0.75rem; line-height: 1rem; }
|
||||
|
||||
@@ -18,7 +18,7 @@ const FAILURE_CATEGORY = {
|
||||
const LOCK_INCIDENT_LINK = 'docs/agent-handoffs/learnings/2026-02-15-relay-health-preflight-job.md';
|
||||
|
||||
function parseArgs(argv) {
|
||||
const args = { cadence: null, platform: process.env.AGENT_PLATFORM || 'codex' };
|
||||
const args = { cadence: null, platform: process.env.AGENT_PLATFORM || 'codex', model: process.env.AGENT_MODEL || null };
|
||||
for (let i = 0; i < argv.length; i += 1) {
|
||||
const value = argv[i];
|
||||
if (!value.startsWith('--') && !args.cadence) {
|
||||
@@ -34,6 +34,10 @@ function parseArgs(argv) {
|
||||
args.platform = argv[i + 1] || args.platform;
|
||||
i += 1;
|
||||
}
|
||||
if (value === '--model') {
|
||||
args.model = argv[i + 1] || args.model;
|
||||
i += 1;
|
||||
}
|
||||
}
|
||||
return args;
|
||||
}
|
||||
@@ -508,8 +512,11 @@ function sleep(ms) {
|
||||
return new Promise((resolve) => setTimeout(resolve, ms));
|
||||
}
|
||||
|
||||
async function acquireLockWithRetry({ selectedAgent, cadence, platform, lockRetry, idempotencyKey }) {
|
||||
async function acquireLockWithRetry({ selectedAgent, cadence, platform, model, lockRetry, idempotencyKey }) {
|
||||
const lockCommandArgs = ['run', 'lock:lock', '--', '--agent', selectedAgent, '--cadence', cadence];
|
||||
if (model) {
|
||||
lockCommandArgs.push('--model', model);
|
||||
}
|
||||
const backoffScheduleMs = [];
|
||||
let attempts = 0;
|
||||
const correlationId = idempotencyKey || `${cadence}:${selectedAgent}:${getRunDateKey()}`;
|
||||
@@ -519,6 +526,7 @@ async function acquireLockWithRetry({ selectedAgent, cadence, platform, lockRetr
|
||||
const result = await runCommand('npm', lockCommandArgs, {
|
||||
env: {
|
||||
AGENT_PLATFORM: platform,
|
||||
...(model ? { AGENT_MODEL: model } : {}),
|
||||
...(idempotencyKey ? { SCHEDULER_LOCK_IDEMPOTENCY_KEY: idempotencyKey } : {}),
|
||||
SCHEDULER_LOCK_CORRELATION_ID: correlationId,
|
||||
SCHEDULER_LOCK_ATTEMPT_ID: String(attempts),
|
||||
@@ -632,7 +640,7 @@ async function writeLog({ cadence, agent, status, reason, detail, platform, meta
|
||||
}
|
||||
|
||||
async function main() {
|
||||
const { cadence, platform } = parseArgs(process.argv.slice(2));
|
||||
const { cadence, platform, model } = parseArgs(process.argv.slice(2));
|
||||
if (!VALID_CADENCES.has(cadence)) {
|
||||
console.error('Usage: node scripts/agent/run-scheduler-cycle.mjs <daily|weekly>');
|
||||
process.exit(1);
|
||||
@@ -740,6 +748,7 @@ async function main() {
|
||||
selectedAgent,
|
||||
cadence,
|
||||
platform,
|
||||
model,
|
||||
lockRetry: schedulerConfig.lockRetry,
|
||||
idempotencyKey: deferralForAgent?.idempotency_key,
|
||||
});
|
||||
@@ -753,7 +762,8 @@ async function main() {
|
||||
const combinedLockOutput = `${lockResult.stderr}\n${lockResult.stdout}`;
|
||||
const diagnosticsSummary = summarizeLockFailureReasons(combinedLockOutput);
|
||||
const backendCategory = lockAttempt.finalBackendCategory || classifyLockBackendError(combinedLockOutput);
|
||||
const lockCommand = `AGENT_PLATFORM=${platform} npm run lock:lock -- --agent ${selectedAgent} --cadence ${cadence}`;
|
||||
const modelPart = model ? ` --model ${model}` : '';
|
||||
const lockCommand = `AGENT_PLATFORM=${platform} npm run lock:lock -- --agent ${selectedAgent} --cadence ${cadence}${modelPart}`;
|
||||
const stderrExcerpt = excerptText(lockResult.stderr);
|
||||
const stdoutExcerpt = excerptText(lockResult.stdout);
|
||||
const backoffSchedule = lockAttempt.backoffScheduleMs.join(', ');
|
||||
@@ -860,7 +870,7 @@ async function main() {
|
||||
|
||||
if (schedulerConfig.memoryPolicy.retrieveCommand) {
|
||||
const retrieveResult = await runCommand('bash', ['-lc', schedulerConfig.memoryPolicy.retrieveCommand], {
|
||||
env: { AGENT_PLATFORM: platform, SCHEDULER_AGENT: selectedAgent, SCHEDULER_CADENCE: cadence, SCHEDULER_PROMPT_PATH: promptPath },
|
||||
env: { AGENT_PLATFORM: platform, ...(model ? { AGENT_MODEL: model } : {}), SCHEDULER_AGENT: selectedAgent, SCHEDULER_CADENCE: cadence, SCHEDULER_PROMPT_PATH: promptPath },
|
||||
});
|
||||
outputChunks.push(retrieveResult.stdout, retrieveResult.stderr);
|
||||
if (retrieveResult.code !== 0) {
|
||||
@@ -879,7 +889,7 @@ async function main() {
|
||||
|
||||
if (schedulerConfig.handoffCommand) {
|
||||
const handoff = await runCommand('bash', ['-lc', schedulerConfig.handoffCommand], {
|
||||
env: { AGENT_PLATFORM: platform, SCHEDULER_AGENT: selectedAgent, SCHEDULER_CADENCE: cadence, SCHEDULER_PROMPT_PATH: promptPath },
|
||||
env: { AGENT_PLATFORM: platform, ...(model ? { AGENT_MODEL: model } : {}), SCHEDULER_AGENT: selectedAgent, SCHEDULER_CADENCE: cadence, SCHEDULER_PROMPT_PATH: promptPath },
|
||||
});
|
||||
outputChunks.push(handoff.stdout, handoff.stderr);
|
||||
if (handoff.code !== 0) {
|
||||
@@ -912,7 +922,7 @@ async function main() {
|
||||
|
||||
if (schedulerConfig.memoryPolicy.storeCommand) {
|
||||
const storeResult = await runCommand('bash', ['-lc', schedulerConfig.memoryPolicy.storeCommand], {
|
||||
env: { AGENT_PLATFORM: platform, SCHEDULER_AGENT: selectedAgent, SCHEDULER_CADENCE: cadence, SCHEDULER_PROMPT_PATH: promptPath },
|
||||
env: { AGENT_PLATFORM: platform, ...(model ? { AGENT_MODEL: model } : {}), SCHEDULER_AGENT: selectedAgent, SCHEDULER_CADENCE: cadence, SCHEDULER_PROMPT_PATH: promptPath },
|
||||
});
|
||||
outputChunks.push(storeResult.stdout, storeResult.stderr);
|
||||
if (storeResult.code !== 0) {
|
||||
@@ -1011,8 +1021,8 @@ async function main() {
|
||||
|
||||
const completeResult = await runCommand(
|
||||
'npm',
|
||||
['run', 'lock:complete', '--', '--agent', selectedAgent, '--cadence', cadence],
|
||||
{ env: { AGENT_PLATFORM: platform } },
|
||||
['run', 'lock:complete', '--', '--agent', selectedAgent, '--cadence', cadence, ...(model ? ['--model', model] : [])],
|
||||
{ env: { AGENT_PLATFORM: platform, ...(model ? { AGENT_MODEL: model } : {}) } },
|
||||
);
|
||||
|
||||
if (completeResult.code !== 0) {
|
||||
|
||||
@@ -43,7 +43,7 @@ const invariants = [
|
||||
],
|
||||
},
|
||||
schedulerSnippets: [
|
||||
"runCommand('npm', ['run', `lock:check:${cadence}`])",
|
||||
"runCommand('npm', ['run', `lock:check:${cadence}`",
|
||||
'checkPayload.excluded',
|
||||
'checkPayload.locked',
|
||||
'checkPayload.paused',
|
||||
|
||||
@@ -31,6 +31,8 @@ export function parseArgs(argv) {
|
||||
allRelaysDownMinutes: null,
|
||||
minSuccessRate: null,
|
||||
windowMinutes: null,
|
||||
platform: null,
|
||||
model: null,
|
||||
};
|
||||
let i = 0;
|
||||
|
||||
@@ -117,6 +119,14 @@ export function parseArgs(argv) {
|
||||
args.windowMinutes = parseInt(argv[++i], 10);
|
||||
} else if (arg.startsWith('--window-minutes=')) {
|
||||
args.windowMinutes = parseInt(arg.split('=')[1], 10);
|
||||
} else if (arg === '--platform') {
|
||||
args.platform = argv[++i];
|
||||
} else if (arg.startsWith('--platform=')) {
|
||||
args.platform = arg.split('=')[1];
|
||||
} else if (arg === '--model') {
|
||||
args.model = argv[++i];
|
||||
} else if (arg.startsWith('--model=')) {
|
||||
args.model = arg.split('=')[1];
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
+23
-7
@@ -33,7 +33,7 @@ import {
|
||||
unpinMemory,
|
||||
} from './services/memory/index.js';
|
||||
import { ExitError } from './errors.mjs';
|
||||
import { todayDateStr, nowUnix, getIsoWeekStr } from './utils.mjs';
|
||||
import { todayDateStr, nowUnix, getIsoWeekStr, detectPlatform } from './utils.mjs';
|
||||
import { runRelayHealthCheck } from './relay-health.mjs';
|
||||
import fs from 'node:fs/promises';
|
||||
import path from 'node:path';
|
||||
@@ -204,7 +204,10 @@ export async function cmdCheck(cadence, deps = {}) {
|
||||
* @returns {Promise<{status: string, eventId: string}>}
|
||||
* @throws {ExitError} If lock is denied (already locked, completed, or race lost)
|
||||
*/
|
||||
export async function cmdLock(agent, cadence, dryRun = false, deps = {}) {
|
||||
export async function cmdLock(agent, cadence, optionsOrDryRun = false, deps = {}) {
|
||||
const options = typeof optionsOrDryRun === 'object' ? optionsOrDryRun : { dryRun: !!optionsOrDryRun };
|
||||
const { dryRun = false, platform = null, model = null } = options;
|
||||
|
||||
const {
|
||||
getRelays = _getRelays,
|
||||
getNamespace = _getNamespace,
|
||||
@@ -290,7 +293,8 @@ export async function cmdLock(agent, cadence, dryRun = false, deps = {}) {
|
||||
status: 'started',
|
||||
namespace,
|
||||
date: dateStr,
|
||||
platform: process.env.AGENT_PLATFORM || 'unknown',
|
||||
platform: platform || process.env.AGENT_PLATFORM || detectPlatform() || 'unknown',
|
||||
model: model || process.env.AGENT_MODEL || 'unknown',
|
||||
lockedAt: new Date(now * 1000).toISOString(),
|
||||
expiresAt: new Date(expiresAt * 1000).toISOString(),
|
||||
}),
|
||||
@@ -436,7 +440,10 @@ export async function cmdList(cadence, deps = {}) {
|
||||
* @returns {Promise<{status: string, eventId: string}>}
|
||||
* @throws {ExitError} If no active lock exists for the agent
|
||||
*/
|
||||
export async function cmdComplete(agent, cadence, dryRun = false, deps = {}) {
|
||||
export async function cmdComplete(agent, cadence, optionsOrDryRun = false, deps = {}) {
|
||||
const options = typeof optionsOrDryRun === 'object' ? optionsOrDryRun : { dryRun: !!optionsOrDryRun };
|
||||
const { dryRun = false, platform = null, model = null } = options;
|
||||
|
||||
const {
|
||||
getRelays = _getRelays,
|
||||
getNamespace = _getNamespace,
|
||||
@@ -500,7 +507,8 @@ export async function cmdComplete(agent, cadence, dryRun = false, deps = {}) {
|
||||
status: 'completed',
|
||||
namespace,
|
||||
date: dateStr,
|
||||
platform: process.env.AGENT_PLATFORM || 'unknown',
|
||||
platform: platform || process.env.AGENT_PLATFORM || detectPlatform() || 'unknown',
|
||||
model: model || process.env.AGENT_MODEL || 'unknown',
|
||||
startedAt: startedAtIso,
|
||||
completedAt: new Date(now * 1000).toISOString(),
|
||||
}),
|
||||
@@ -614,7 +622,11 @@ export async function main(argv) {
|
||||
console.error(`ERROR: --cadence <${[...VALID_CADENCES].join('|')}> is required for lock`);
|
||||
throw new ExitError(1, 'Missing cadence');
|
||||
}
|
||||
await cmdLock(args.agent, args.cadence, args.dryRun);
|
||||
await cmdLock(args.agent, args.cadence, {
|
||||
dryRun: args.dryRun,
|
||||
platform: args.platform,
|
||||
model: args.model
|
||||
});
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -627,7 +639,11 @@ export async function main(argv) {
|
||||
console.error(`ERROR: --cadence <${[...VALID_CADENCES].join('|')}> is required for complete`);
|
||||
throw new ExitError(1, 'Missing cadence');
|
||||
}
|
||||
await cmdComplete(args.agent, args.cadence, args.dryRun);
|
||||
await cmdComplete(args.agent, args.cadence, {
|
||||
dryRun: args.dryRun,
|
||||
platform: args.platform,
|
||||
model: args.model
|
||||
});
|
||||
break;
|
||||
}
|
||||
|
||||
|
||||
@@ -27,3 +27,10 @@ export function getIsoWeekStr(dateInput) {
|
||||
|
||||
return `${date.getUTCFullYear()}-W${String(weekNo).padStart(2, '0')}`;
|
||||
}
|
||||
|
||||
export function detectPlatform() {
|
||||
if (process.env.JULES_API_KEY || process.env.JULES_SESSION_ID) return 'jules';
|
||||
if (process.env.CODEX_API_KEY || process.env.CODEX_SESSION_ID) return 'codex';
|
||||
if (process.env.GOOSE_API_KEY || process.env.GOOSE_SESSION_ID) return 'goose';
|
||||
return null;
|
||||
}
|
||||
@@ -129,7 +129,7 @@ describe('Scheduler cycle ordering guarantees', () => {
|
||||
|
||||
const order = [
|
||||
"const preflight = await runLockHealthPreflight({ cadence, platform });",
|
||||
"const checkResult = await runCommand('npm', ['run', `lock:check:${cadence}`]);",
|
||||
"const checkResult = await runCommand('npm', ['run', `lock:check:${cadence}`",
|
||||
"const lockAttempt = await acquireLockWithRetry({",
|
||||
"if (schedulerConfig.handoffCommand)",
|
||||
"const artifactCheck = await runCommand('node', [",
|
||||
|
||||
File diff suppressed because it is too large.
Load diff
Reference in new issue
Block a user