agent-relay 3.2.0 → 3.2.1

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 (48) hide show
  1. package/bin/agent-relay-broker-darwin-arm64 +0 -0
  2. package/bin/agent-relay-broker-darwin-x64 +0 -0
  3. package/bin/agent-relay-broker-linux-arm64 +0 -0
  4. package/bin/agent-relay-broker-linux-x64 +0 -0
  5. package/dist/index.cjs +1307 -204
  6. package/dist/src/cli/relaycast-mcp.d.ts +4 -0
  7. package/dist/src/cli/relaycast-mcp.d.ts.map +1 -1
  8. package/dist/src/cli/relaycast-mcp.js +4 -4
  9. package/dist/src/cli/relaycast-mcp.js.map +1 -1
  10. package/package.json +8 -8
  11. package/packages/acp-bridge/package.json +2 -2
  12. package/packages/config/package.json +1 -1
  13. package/packages/hooks/package.json +4 -4
  14. package/packages/memory/package.json +2 -2
  15. package/packages/openclaw/package.json +2 -2
  16. package/packages/policy/package.json +2 -2
  17. package/packages/sdk/dist/__tests__/completion-pipeline.test.d.ts +14 -0
  18. package/packages/sdk/dist/__tests__/completion-pipeline.test.d.ts.map +1 -0
  19. package/packages/sdk/dist/__tests__/completion-pipeline.test.js +1476 -0
  20. package/packages/sdk/dist/__tests__/completion-pipeline.test.js.map +1 -0
  21. package/packages/sdk/dist/__tests__/e2e-owner-review.test.js +2 -2
  22. package/packages/sdk/dist/__tests__/e2e-owner-review.test.js.map +1 -1
  23. package/packages/sdk/dist/workflows/runner.d.ts +53 -2
  24. package/packages/sdk/dist/workflows/runner.d.ts.map +1 -1
  25. package/packages/sdk/dist/workflows/runner.js +1269 -86
  26. package/packages/sdk/dist/workflows/runner.js.map +1 -1
  27. package/packages/sdk/dist/workflows/trajectory.d.ts +6 -2
  28. package/packages/sdk/dist/workflows/trajectory.d.ts.map +1 -1
  29. package/packages/sdk/dist/workflows/trajectory.js +37 -2
  30. package/packages/sdk/dist/workflows/trajectory.js.map +1 -1
  31. package/packages/sdk/dist/workflows/types.d.ts +88 -0
  32. package/packages/sdk/dist/workflows/types.d.ts.map +1 -1
  33. package/packages/sdk/dist/workflows/types.js.map +1 -1
  34. package/packages/sdk/package.json +2 -2
  35. package/packages/sdk/src/__tests__/completion-pipeline.test.ts +1820 -0
  36. package/packages/sdk/src/__tests__/e2e-owner-review.test.ts +2 -2
  37. package/packages/sdk/src/__tests__/idle-nudge.test.ts +68 -0
  38. package/packages/sdk/src/__tests__/workflow-runner.test.ts +113 -4
  39. package/packages/sdk/src/workflows/README.md +43 -11
  40. package/packages/sdk/src/workflows/runner.ts +1751 -94
  41. package/packages/sdk/src/workflows/schema.json +6 -0
  42. package/packages/sdk/src/workflows/trajectory.ts +52 -3
  43. package/packages/sdk/src/workflows/types.ts +149 -0
  44. package/packages/sdk-py/pyproject.toml +1 -1
  45. package/packages/telemetry/package.json +1 -1
  46. package/packages/trajectory/package.json +2 -2
  47. package/packages/user-directory/package.json +2 -2
  48. package/packages/utils/package.json +2 -2
@@ -126,6 +126,12 @@ Added workdir to WorktreeWorkflowStep
126
126
  },
127
127
  "idleNudge": {
128
128
  "$ref": "#/definitions/IdleNudgeConfig"
129
+ },
130
+ "completionGracePeriodMs": {
131
+ "type": "integer",
132
+ "minimum": 0,
133
+ "default": 5000,
134
+ "description": "Grace period (ms) after an agent exits with code 0 but without posting the expected coordination signal. During this window the runner checks verification gates and evidence before failing. Set to 0 to disable."
129
135
  }
130
136
  }
131
137
  },
@@ -16,7 +16,7 @@ import { existsSync } from 'node:fs';
16
16
  import { mkdir, writeFile, rename } from 'node:fs/promises';
17
17
  import path from 'node:path';
18
18
 
19
- import type { TrajectoryConfig, WorkflowStep } from './types.js';
19
+ import type { StepCompletionDecision, TrajectoryConfig, WorkflowStep } from './types.js';
20
20
 
21
21
  // ── Trajectory file format (compatible with trail CLI) ───────────────────────
22
22
 
@@ -84,6 +84,8 @@ export interface StepOutcome {
84
84
  nonInteractive?: boolean;
85
85
  /** Duration in ms. */
86
86
  durationMs?: number;
87
+ /** How the step completion was determined. */
88
+ completionMode?: StepCompletionDecision['mode'];
87
89
  }
88
90
 
89
91
  // ── Failure root-cause categories ───────────────────────────────────────────
@@ -339,8 +341,35 @@ export class WorkflowTrajectory {
339
341
  await this.flush();
340
342
  }
341
343
 
344
+ async stepCompletionDecision(stepName: string, decision: StepCompletionDecision): Promise<void> {
345
+ if (!this.enabled || !this.trajectory) return;
346
+
347
+ const modeLabel = decision.mode === 'marker' ? 'marker-based' : `${decision.mode}-based`;
348
+ const reason = decision.reason ? ` — ${decision.reason}` : '';
349
+ const evidence = this.formatCompletionEvidenceSummary(decision.evidence);
350
+ const evidenceSuffix = evidence ? ` (${evidence})` : '';
351
+
352
+ this.addEvent(
353
+ decision.mode === 'marker' ? 'completion-marker' : 'completion-evidence',
354
+ `"${stepName}" ${modeLabel} completion${reason}${evidenceSuffix}`,
355
+ 'medium',
356
+ {
357
+ stepName,
358
+ completionMode: decision.mode,
359
+ reason: decision.reason,
360
+ evidence: decision.evidence,
361
+ }
362
+ );
363
+ await this.flush();
364
+ }
365
+
342
366
  /** Record step completed — captures what was accomplished. */
343
- async stepCompleted(step: WorkflowStep, output: string, attempt: number): Promise<void> {
367
+ async stepCompleted(
368
+ step: WorkflowStep,
369
+ output: string,
370
+ attempt: number,
371
+ decision?: StepCompletionDecision
372
+ ): Promise<void> {
344
373
  if (!this.enabled || !this.trajectory) return;
345
374
 
346
375
  const suffix = attempt > 1 ? ` (after ${attempt} attempts)` : '';
@@ -357,7 +386,12 @@ export class WorkflowTrajectory {
357
386
  ? lastMeaningful
358
387
  : output.trim().slice(0, 120) || '(no output)';
359
388
 
360
- this.addEvent('finding', `"${step.name}" completed${suffix} → ${completion}`, 'medium');
389
+ if (decision) {
390
+ await this.stepCompletionDecision(step.name, decision);
391
+ }
392
+
393
+ const modeSuffix = decision ? ` [${decision.mode}]` : '';
394
+ this.addEvent('finding', `"${step.name}" completed${suffix}${modeSuffix} → ${completion}`, 'medium');
361
395
  await this.flush();
362
396
  }
363
397
 
@@ -697,6 +731,21 @@ export class WorkflowTrajectory {
697
731
  chapter.events.push(event);
698
732
  }
699
733
 
734
+ private formatCompletionEvidenceSummary(
735
+ evidence: StepCompletionDecision['evidence'] | undefined
736
+ ): string | undefined {
737
+ if (!evidence) return undefined;
738
+
739
+ const parts: string[] = [];
740
+ if (evidence.summary) parts.push(evidence.summary);
741
+ if (evidence.signals?.length) parts.push(`signals=${evidence.signals.join(', ')}`);
742
+ if (evidence.channelPosts?.length) parts.push(`channel=${evidence.channelPosts.join(' | ')}`);
743
+ if (evidence.files?.length) parts.push(`files=${evidence.files.join(', ')}`);
744
+ if (evidence.exitCode !== undefined) parts.push(`exit=${evidence.exitCode}`);
745
+
746
+ return parts.length > 0 ? parts.join('; ') : undefined;
747
+ }
748
+
700
749
  private async flush(): Promise<void> {
701
750
  if (!this.trajectory) return;
702
751
 
@@ -76,6 +76,13 @@ export interface SwarmConfig {
76
76
  channel?: string;
77
77
  /** Idle agent detection and nudging configuration for interactive agents. */
78
78
  idleNudge?: IdleNudgeConfig;
79
+ /**
80
+ * Grace period (ms) after an agent exits with code 0 but without posting
81
+ * the expected coordination signal. During this window the runner checks
82
+ * verification gates and evidence before failing the step.
83
+ * Default: 5000 (5 seconds). Set to 0 to disable.
84
+ */
85
+ completionGracePeriodMs?: number;
79
86
  }
80
87
 
81
88
  export type SwarmPattern =
@@ -310,6 +317,128 @@ export interface VerificationCheck {
310
317
  description?: string;
311
318
  }
312
319
 
320
+ // ── Completion evidence ─────────────────────────────────────────────────────
321
+
322
+ export type CompletionEvidenceSignalSource =
323
+ | 'channel'
324
+ | 'stdout'
325
+ | 'stderr'
326
+ | 'process'
327
+ | 'filesystem'
328
+ | 'tool'
329
+ | 'verification';
330
+
331
+ export type CompletionEvidenceSignalKind =
332
+ | 'worker_done'
333
+ | 'lead_done'
334
+ | 'step_complete'
335
+ | 'owner_decision'
336
+ | 'review_decision'
337
+ | 'task_summary'
338
+ | 'verification_passed'
339
+ | 'verification_failed'
340
+ | 'process_exit'
341
+ | 'custom';
342
+
343
+ export interface CompletionEvidenceSignal {
344
+ kind: CompletionEvidenceSignalKind;
345
+ source: CompletionEvidenceSignalSource;
346
+ text: string;
347
+ observedAt: string;
348
+ sender?: string;
349
+ actor?: string;
350
+ role?: string;
351
+ value?: string;
352
+ }
353
+
354
+ export type CompletionEvidenceChannelOrigin = 'runner_post' | 'forwarded_chunk' | 'relay_message';
355
+
356
+ export interface CompletionEvidenceChannelPost {
357
+ stepName: string;
358
+ text: string;
359
+ postedAt: string;
360
+ origin: CompletionEvidenceChannelOrigin;
361
+ completionRelevant: boolean;
362
+ sender?: string;
363
+ actor?: string;
364
+ role?: string;
365
+ target?: string;
366
+ signals: CompletionEvidenceSignal[];
367
+ }
368
+
369
+ export type CompletionEvidenceFileChangeKind = 'created' | 'modified' | 'deleted';
370
+
371
+ export interface CompletionEvidenceFileChange {
372
+ path: string;
373
+ kind: CompletionEvidenceFileChangeKind;
374
+ observedAt: string;
375
+ root?: string;
376
+ }
377
+
378
+ export type CompletionEvidenceToolSideEffectType =
379
+ | 'persist_step_output'
380
+ | 'post_channel_message'
381
+ | 'verification_observed'
382
+ | 'worktree_created'
383
+ | 'owner_monitoring'
384
+ | 'review_started'
385
+ | 'review_completed'
386
+ | 'worker_exit'
387
+ | 'worker_error'
388
+ | 'retry'
389
+ | 'custom';
390
+
391
+ export interface CompletionEvidenceToolSideEffect {
392
+ type: CompletionEvidenceToolSideEffectType;
393
+ detail: string;
394
+ observedAt: string;
395
+ raw?: Record<string, unknown>;
396
+ }
397
+
398
+ export interface StepCompletionEvidence {
399
+ stepName: string;
400
+ status?: WorkflowStepStatus;
401
+ startedAt?: string;
402
+ completedAt?: string;
403
+ lastUpdatedAt: string;
404
+ roots: string[];
405
+ output: {
406
+ stdout: string;
407
+ stderr: string;
408
+ combined: string;
409
+ };
410
+ channelPosts: CompletionEvidenceChannelPost[];
411
+ files: CompletionEvidenceFileChange[];
412
+ process: {
413
+ exitCode?: number;
414
+ exitSignal?: string;
415
+ };
416
+ toolSideEffects: CompletionEvidenceToolSideEffect[];
417
+ coordinationSignals: CompletionEvidenceSignal[];
418
+ }
419
+
420
+ export type StepCompletionMode =
421
+ | 'marker'
422
+ | 'evidence'
423
+ | 'verification'
424
+ | 'owner_decision'
425
+ | 'review'
426
+ | 'heuristic';
427
+
428
+ export interface StepCompletionDecisionEvidence {
429
+ summary?: string;
430
+ signals?: string[];
431
+ channelPosts?: string[];
432
+ files?: string[];
433
+ exitCode?: number;
434
+ }
435
+
436
+ export interface StepCompletionDecision {
437
+ mode: StepCompletionMode;
438
+ reason?: string;
439
+ evidence?: StepCompletionDecisionEvidence;
440
+ }
441
+
313
442
  // ── Coordination ────────────────────────────────────────────────────────────
314
443
 
315
444
  /** Coordination settings for multi-agent synchronization. */
@@ -394,6 +523,25 @@ export interface WorkflowRunRow {
394
523
  }
395
524
 
396
525
  export type WorkflowStepStatus = 'pending' | 'running' | 'completed' | 'failed' | 'skipped';
526
+ export type WorkflowOwnerDecision =
527
+ | 'COMPLETE'
528
+ | 'INCOMPLETE_RETRY'
529
+ | 'INCOMPLETE_FAIL'
530
+ | 'NEEDS_CLARIFICATION';
531
+ /**
532
+ * Completion reasons are recorded for both successful and failed steps.
533
+ * `retry_requested_by_owner` is a retry-control signal, not a success state:
534
+ * the runner retries while budget remains and fails the step once retries are exhausted.
535
+ */
536
+ export type WorkflowStepCompletionReason =
537
+ | 'completed_verified'
538
+ | 'completed_by_owner_decision'
539
+ | 'completed_by_evidence'
540
+ | 'completed_by_process_exit'
541
+ | 'retry_requested_by_owner'
542
+ | 'failed_verification'
543
+ | 'failed_owner_decision'
544
+ | 'failed_no_evidence';
397
545
 
398
546
  /** Database row representing a single workflow step execution. */
399
547
  export interface WorkflowStepRow {
@@ -410,6 +558,7 @@ export interface WorkflowStepRow {
410
558
  dependsOn: string[];
411
559
  output?: string;
412
560
  error?: string;
561
+ completionReason?: WorkflowStepCompletionReason;
413
562
  startedAt?: string;
414
563
  completedAt?: string;
415
564
  retryCount: number;
@@ -4,7 +4,7 @@ build-backend = "hatchling.build"
4
4
 
5
5
  [project]
6
6
  name = "agent-relay-sdk"
7
- version = "3.2.0"
7
+ version = "3.2.1"
8
8
  description = "Python SDK for Agent Relay workflows"
9
9
  readme = "README.md"
10
10
  license = "Apache-2.0"
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@agent-relay/telemetry",
3
- "version": "3.2.0",
3
+ "version": "3.2.1",
4
4
  "description": "Anonymous telemetry for Agent Relay usage analytics",
5
5
  "type": "module",
6
6
  "main": "dist/index.js",
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@agent-relay/trajectory",
3
- "version": "3.2.0",
3
+ "version": "3.2.1",
4
4
  "description": "Trajectory integration utilities (trail/PDERO) for Relay",
5
5
  "type": "module",
6
6
  "main": "dist/index.js",
@@ -22,7 +22,7 @@
22
22
  "test:watch": "vitest"
23
23
  },
24
24
  "dependencies": {
25
- "@agent-relay/config": "3.2.0"
25
+ "@agent-relay/config": "3.2.1"
26
26
  },
27
27
  "devDependencies": {
28
28
  "@types/node": "^22.19.3",
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@agent-relay/user-directory",
3
- "version": "3.2.0",
3
+ "version": "3.2.1",
4
4
  "description": "User directory service for agent-relay (per-user credential storage)",
5
5
  "type": "module",
6
6
  "main": "dist/index.js",
@@ -22,7 +22,7 @@
22
22
  "test:watch": "vitest"
23
23
  },
24
24
  "dependencies": {
25
- "@agent-relay/utils": "3.2.0"
25
+ "@agent-relay/utils": "3.2.1"
26
26
  },
27
27
  "devDependencies": {
28
28
  "@types/node": "^22.19.3",
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@agent-relay/utils",
3
- "version": "3.2.0",
3
+ "version": "3.2.1",
4
4
  "description": "Shared utilities for agent-relay: logging, name generation, command resolution, update checking",
5
5
  "type": "module",
6
6
  "main": "dist/cjs/index.js",
@@ -112,7 +112,7 @@
112
112
  "vitest": "^3.2.4"
113
113
  },
114
114
  "dependencies": {
115
- "@agent-relay/config": "3.2.0",
115
+ "@agent-relay/config": "3.2.1",
116
116
  "compare-versions": "^6.1.1"
117
117
  },
118
118
  "publishConfig": {