agents-relay 2.0.175 → 2.0.177

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/dist/adapters.js CHANGED
@@ -389,7 +389,7 @@ export class ChatGptAdapter {
389
389
  const referencePrompt = task.chatgptThreadDelivery && references.length
390
390
  ? `\n\n[Inline immutable local reference snapshots]\nThese complete verified snapshots are included in this message because this thread delivery does not attach local files. Follow their contents according to their declared roles.\n${references.map(reference => `\n--- ${reference.role}: ${reference.path} (sha256:${reference.sha256}) ---\n${reference.content}\n--- end snapshot ---`).join('\n')}`
391
391
  : references.length
392
- ? `\n\n[Attached immutable Agent Contract]\nAfter publishing the required task.started event, read the attached contract file and verify its SHA-256 before following it. If it is unreadable or mismatched, report a concrete failure.\n${references.map(reference => `- ${reference.path} (sha256:${reference.sha256})`).join('\n')}`
392
+ ? `\n\n[Attached immutable Agent Contract]\nAfter publishing the required task.started event, read the attached immutable contract snapshot and follow it. Relay owns snapshot integrity; do not hash or compare the original .agent.md. If the attached snapshot is unreadable, report a concrete failure.\n${references.map(reference => `- ${reference.path} (sha256:${reference.sha256})`).join('\n')}`
393
393
  : '';
394
394
  if (task.chatgptThreadDelivery && declaredPromptReferences(task.input).length) {
395
395
  const unresolved = declaredPromptReferences(task.input)
@@ -72,7 +72,7 @@ export async function buildReferenceFirstPrompt(input) {
72
72
  return buildAgentPrompt({
73
73
  role: input.role,
74
74
  system: (input.bootstrap ? input.bootstrap.trim() + '\n' : '') +
75
- 'After the required execution startup action, read the referenced immutable Agent Contract. Verify its SHA-256 before following it. If unreadable or mismatched, report a concrete failure; never guess its instructions.',
75
+ 'After the required execution startup action, read the referenced immutable Agent Contract snapshot and follow it. Relay owns snapshot integrity and version identity; do not compute a hash of the source .agent.md or compare it to the snapshot. If the snapshot is unreadable, report a concrete failure; never guess its instructions.',
76
76
  user: input.user,
77
77
  references: [reference],
78
78
  });
@@ -0,0 +1,40 @@
1
+ import { readFile } from 'node:fs/promises';
2
+ import { Ajv } from 'ajv';
3
+ /** Explicit, read-only validation. Projects own schemas and decide when to call it. */
4
+ export async function validateArtifact(artifactPath, schemaPath) {
5
+ if (!artifactPath || !schemaPath)
6
+ throw new Error('artifact validate requires --artifact and --schema');
7
+ const [artifactText, schemaText] = await Promise.all([
8
+ readFile(artifactPath, 'utf8'),
9
+ readFile(schemaPath, 'utf8'),
10
+ ]);
11
+ const artifact = JSON.parse(artifactText);
12
+ const schema = JSON.parse(schemaText);
13
+ if (!schema || typeof schema !== 'object' || Array.isArray(schema))
14
+ throw new Error('Schema must be a JSON object');
15
+ if ('$async' in schema)
16
+ throw new Error('Async schemas are not supported');
17
+ const validate = new Ajv({ allErrors: true, strict: false }).compile(schema);
18
+ const valid = validate(artifact);
19
+ if (typeof valid !== 'boolean')
20
+ throw new Error('Async validation is not supported');
21
+ return {
22
+ valid,
23
+ errors: (validate.errors ?? []).map(error => ({
24
+ path: error.instancePath || '/',
25
+ message: error.message ?? 'invalid value',
26
+ })),
27
+ };
28
+ }
29
+ export async function runArtifactCommand(action, args) {
30
+ if (action !== 'validate')
31
+ throw new Error('artifact supports only validate');
32
+ const value = (flag) => {
33
+ const index = args.indexOf(flag);
34
+ return index < 0 ? '' : args[index + 1] ?? '';
35
+ };
36
+ const result = await validateArtifact(value('--artifact'), value('--schema'));
37
+ console.log(JSON.stringify(result, null, 2));
38
+ if (!result.valid)
39
+ throw new Error('Artifact validation failed');
40
+ }
package/dist/cli-help.js CHANGED
@@ -1,4 +1,4 @@
1
- export const usage = 'agents-relay <job|task|review|plan|blocker|projection|escalation|context|init|record|agent-register|agent-discover|status|reconcile|serve> [options]';
1
+ export const usage = 'agents-relay <job|task|review|artifact|plan|blocker|projection|escalation|context|init|record|agent-register|agent-discover|status|reconcile|serve> [options]';
2
2
  const help = {
3
3
  root: `Agents Relay coordinates durable asynchronous agent jobs through local SQLite and workflow graphs.
4
4
 
@@ -11,6 +11,7 @@ Commands:
11
11
  job create|update|show|list|merge|unblock|cancel|pause|resume Manage SQLite-authoritative jobs with optional GitHub PRs
12
12
  task create|update|show|list|classify|complete|retry|unblock|cancel Manage durable tasks
13
13
  review request Request graph-owned review (optional thread override)
14
+ artifact validate Check a JSON artifact against a project-owned JSON Schema
14
15
  plan Invoke the Planner for an existing managed Job
15
16
  plan apply Submit a validated Task Tree within one active Plan
16
17
  blocker add|resolve|show Manage cross-Job blocker dependencies
@@ -60,6 +61,10 @@ Request a new SHA-bound reviewer turn through the existing Relay lifecycle.
60
61
  Usage: npx agents-relay review request --repo OWNER/REPO --pr NUMBER --id JOB_ID [--thread-id THREAD_ID]
61
62
 
62
63
  When provided, --thread-id persists a reviewer destination; otherwise the Job reviewer thread, then creator thread, then legacy review route is used. The command wakes Relay. Review Task creation, idempotency, routing and delivery remain graph/daemon-owned. Rejects in-flight/queued reviews; does not itself mark review delivered.`,
64
+ artifact: `Check a JSON artifact against a project-owned JSON Schema. Read-only; does not affect Task state or planning.
65
+
66
+ Usage: agents-relay artifact validate --artifact PATH --schema PATH
67
+ Exit 0 on PASS, 1 on schema mismatch or invalid input. Returns JSON { valid, errors }.`,
63
68
  'review run': `Evaluate the calling Agent's requested outcome inside its Worker. A generic Outcome Reviewer runs by default; --agents adds comma-separated professional roles found in the project or shared agent catalog. Does not create Relay Tasks or trigger Final Review.
64
69
 
65
70
  Usage: agents-relay review run (--prompt TEXT | --prompt-file PATH) [--project-path DIR] [--agents role,role] [--output PATH]
package/dist/cli.js CHANGED
@@ -1,4 +1,5 @@
1
1
  #!/usr/bin/env node
2
+ import { runArtifactCommand } from './cli-artifact.js';
2
3
  import { runWorkflowAction } from './cli-workflow-action.js';
3
4
  import { workflowCliResult } from './cli-workflow.js';
4
5
  import { configureLocalGitMerge } from './cli-local-merge-config.js';
@@ -743,6 +744,11 @@ async function main() {
743
744
  await runJobCommand(action ?? '', jobArgs);
744
745
  return;
745
746
  }
747
+ if (command === 'artifact') {
748
+ const [action, ...artifactArgs] = args;
749
+ await runArtifactCommand(action ?? '', artifactArgs);
750
+ return;
751
+ }
746
752
  if (command === 'task') {
747
753
  const [action, ...taskArgs] = args;
748
754
  await runTaskCommand(action ?? '', taskArgs);
@@ -242,11 +242,10 @@ export async function resolveAgentContract(context, agentName) {
242
242
  return { agent, definition, hash: resolved.hash, sources: resolved.sources };
243
243
  }
244
244
  export async function agentContractPrompt(context, agentName) {
245
- const { agent, definition, hash, sources } = await resolveAgentContract(context, agentName);
245
+ const { agent, definition, sources } = await resolveAgentContract(context, agentName);
246
246
  return `[Selected task agent contract]
247
247
  Agent: ${agent.name}
248
248
  Source: ${agent.path ?? agent.source}
249
- Effective contract SHA-256: ${hash}
250
249
  Contract layers: ${sources.join(' -> ')}
251
250
 
252
251
  The following Markdown is the authoritative behavioral contract for this Task agent.
package/dist/planner.js CHANGED
@@ -498,7 +498,7 @@ export class AgentObjectivePlanner {
498
498
  const instructions = effectivePlanner?.content ?? await readFile(this.agentFile, 'utf8');
499
499
  const contract = await readFile(DEFAULT_TASK_JOB_CONTRACT, 'utf8');
500
500
  const resolvedContext = context.executionContext ? executionContextPrompt(context.executionContext) + '\n\n' : '';
501
- const prompt = renderAgentPrompt(await buildReferenceFirstPrompt({ role: 'planner', adapter: 'codex', system: (effectivePlanner ? `[Effective planner contract SHA-256: ${effectivePlanner.hash}]\n\n` : '') + instructions.trim() + '\n\n## Shared Task / Job Contract\n\n' + contract.trim(), user: resolvedContext + '## Durable planner input\n\n' + plannerInput(context) }), 'codex');
501
+ const prompt = renderAgentPrompt(await buildReferenceFirstPrompt({ role: 'planner', adapter: 'codex', system: instructions.trim() + '\n\n## Shared Task / Job Contract\n\n' + contract.trim(), user: resolvedContext + '## Durable planner input\n\n' + plannerInput(context) }), 'codex');
502
502
  const runAgent = (input) => new Promise((resolve, reject) => {
503
503
  // Plan apply writes unified relay.sqlite beside AGENTS_RELAY_STORE_DIR.
504
504
  const child = spawnOwnedProcess(this.command, buildPlannerCodexArgs(relayStoreDirectory(), input), { invocation: 'planner.agent', signal, correlation: { jobId: context.job.id }, spawn: { cwd: context.executionContext?.project.path, stdio: ['ignore', 'pipe', 'pipe'] } });
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "agents-relay",
3
- "version": "2.0.175",
3
+ "version": "2.0.177",
4
4
  "description": "Durable async agent jobs coordinated through GitHub pull requests",
5
5
  "repository": {
6
6
  "type": "git",
@@ -45,5 +45,8 @@
45
45
  "workflow",
46
46
  "README.md",
47
47
  "LICENSE"
48
- ]
48
+ ],
49
+ "dependencies": {
50
+ "ajv": "^8.20.0"
51
+ }
49
52
  }