opencode-swarm 6.80.2 → 6.81.0

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/README.md CHANGED
@@ -91,6 +91,60 @@ All project state lives in `.swarm/`:
91
91
 
92
92
  Swarm is resumable by design. If `.swarm/` already exists, the architect goes straight into **RESUME** → **EXECUTE** instead of repeating discovery.
93
93
 
94
+ ## Process Remediation Model (PRM)
95
+
96
+ Swarm includes a lightweight Process Remediation Model that monitors agent trajectories and injects course-correction guidance before loops form. Based on research from SWE-PRM (arXiv 2509.02360), taxonomy-guided PRMs improve task resolution by detecting failure patterns early.
97
+
98
+ ### Detected Patterns
99
+
100
+ The PRM detects five trajectory patterns:
101
+
102
+ 1. **Repetition Loop** — Same agent performs the same action on the same target file repeatedly
103
+ 2. **Ping-Pong** — Agent A hands off to B, B hands back to A, and A hands to B again
104
+ 3. **Expansion Drift** — Successive plans grow in scope beyond the original task
105
+ 4. **Stuck-on-Test** — Coder edits → tests fail → coder edits same file → tests fail, repeating
106
+ 5. **Context Thrashing** — Agent requests increasingly large file sets without narrowing scope
107
+
108
+ ### Escalation Protocol
109
+
110
+ When a pattern is detected, the PRM tracks escalation levels:
111
+
112
+ - **Level 1 (1st detection):** Course-correction guidance is added to `pendingAdvisoryMessages` and injected via the `[ADVISORIES]` block. Sets `escalationLevel = 1`.
113
+ - **Level 2 (2nd detection):** Additional guidance added to `pendingAdvisoryMessages`, `architectAlertPending = true` is set, and `telemetry.prmEscalationTriggered()` is emitted. Sets `escalationLevel = 2`.
114
+ - **Level 3 (3rd+ detection):** Guidance added to `pendingAdvisoryMessages`, plus a hard stop directive is injected separately via `[HARD STOP]` block. Sets `escalationLevel = 3` and `hardStopPending = true`. Emits `telemetry.prmHardStop()`.
115
+
116
+ ### Configuration
117
+
118
+ PRM behavior is controlled via the `prm` section in your configuration:
119
+
120
+ ```json
121
+ {
122
+ "prm": {
123
+ "enabled": true,
124
+ "pattern_thresholds": {
125
+ "repetition_loop": 2,
126
+ "ping_pong": 4,
127
+ "expansion_drift": 3,
128
+ "stuck_on_test": 3,
129
+ "context_thrash": 5
130
+ },
131
+ "max_trajectory_lines": 100,
132
+ "escalation_enabled": true,
133
+ "detection_timeout_ms": 5000
134
+ }
135
+ }
136
+ ```
137
+
138
+ > **Note:** `max_trajectory_lines`, `escalation_enabled`, and `detection_timeout_ms` are defined in the schema but not yet enforced at runtime. The default trajectory limit is 1000 lines.
139
+
140
+ ### Replay Recording
141
+
142
+ PRM records all pattern detections, course corrections, escalations, and hard stops to `.swarm/replays/{sessionId}-{timestamp}.jsonl` for post-mortem analysis. Use the replay artifacts to understand why loops formed and how they were resolved.
143
+
144
+ ### Performance
145
+
146
+ Pattern detection runs in less than 100ms per step using rule-based analysis — no LLM calls required for detection.
147
+
94
148
  ---
95
149
 
96
150
  ## Quick Start
package/dist/cli/index.js CHANGED
@@ -19424,6 +19424,25 @@ var CompactionConfigSchema = exports_external.object({
19424
19424
  emergencyThreshold: exports_external.number().min(1).max(99).default(80),
19425
19425
  preserveLastNTurns: exports_external.number().int().min(1).default(5)
19426
19426
  });
19427
+ var PrmConfigSchema = exports_external.object({
19428
+ enabled: exports_external.boolean().default(true),
19429
+ pattern_thresholds: exports_external.object({
19430
+ repetition_loop: exports_external.number().min(1).default(2),
19431
+ ping_pong: exports_external.number().min(1).default(2),
19432
+ expansion_drift: exports_external.number().min(1).default(3),
19433
+ stuck_on_test: exports_external.number().min(1).default(3),
19434
+ context_thrash: exports_external.number().min(1).default(3)
19435
+ }).default(() => ({
19436
+ repetition_loop: 2,
19437
+ ping_pong: 2,
19438
+ expansion_drift: 3,
19439
+ stuck_on_test: 3,
19440
+ context_thrash: 3
19441
+ })),
19442
+ max_trajectory_lines: exports_external.number().min(10).default(1000),
19443
+ escalation_enabled: exports_external.boolean().default(true),
19444
+ detection_timeout_ms: exports_external.number().min(10).default(100)
19445
+ });
19427
19446
  var AgentAuthorityRuleSchema = exports_external.object({
19428
19447
  readOnly: exports_external.boolean().optional(),
19429
19448
  blockedExact: exports_external.array(exports_external.string()).optional(),
@@ -19504,6 +19523,7 @@ var PluginConfigSchema = exports_external.object({
19504
19523
  }).optional(),
19505
19524
  incremental_verify: IncrementalVerifyConfigSchema.optional(),
19506
19525
  compaction_service: CompactionConfigSchema.optional(),
19526
+ prm: PrmConfigSchema.optional(),
19507
19527
  council: CouncilConfigSchema.optional(),
19508
19528
  parallelization: ParallelizationConfigSchema.optional(),
19509
19529
  turbo_mode: exports_external.boolean().default(false).optional(),
@@ -477,6 +477,20 @@ export declare const CompactionConfigSchema: z.ZodObject<{
477
477
  preserveLastNTurns: z.ZodDefault<z.ZodNumber>;
478
478
  }, z.core.$strip>;
479
479
  export type CompactionConfig = z.infer<typeof CompactionConfigSchema>;
480
+ export declare const PrmConfigSchema: z.ZodObject<{
481
+ enabled: z.ZodDefault<z.ZodBoolean>;
482
+ pattern_thresholds: z.ZodDefault<z.ZodObject<{
483
+ repetition_loop: z.ZodDefault<z.ZodNumber>;
484
+ ping_pong: z.ZodDefault<z.ZodNumber>;
485
+ expansion_drift: z.ZodDefault<z.ZodNumber>;
486
+ stuck_on_test: z.ZodDefault<z.ZodNumber>;
487
+ context_thrash: z.ZodDefault<z.ZodNumber>;
488
+ }, z.core.$strip>>;
489
+ max_trajectory_lines: z.ZodDefault<z.ZodNumber>;
490
+ escalation_enabled: z.ZodDefault<z.ZodBoolean>;
491
+ detection_timeout_ms: z.ZodDefault<z.ZodNumber>;
492
+ }, z.core.$strip>;
493
+ export type PrmConfig = z.infer<typeof PrmConfigSchema>;
480
494
  export declare const AgentAuthorityRuleSchema: z.ZodObject<{
481
495
  readOnly: z.ZodOptional<z.ZodBoolean>;
482
496
  blockedExact: z.ZodOptional<z.ZodArray<z.ZodString>>;
@@ -886,6 +900,19 @@ export declare const PluginConfigSchema: z.ZodObject<{
886
900
  emergencyThreshold: z.ZodDefault<z.ZodNumber>;
887
901
  preserveLastNTurns: z.ZodDefault<z.ZodNumber>;
888
902
  }, z.core.$strip>>;
903
+ prm: z.ZodOptional<z.ZodObject<{
904
+ enabled: z.ZodDefault<z.ZodBoolean>;
905
+ pattern_thresholds: z.ZodDefault<z.ZodObject<{
906
+ repetition_loop: z.ZodDefault<z.ZodNumber>;
907
+ ping_pong: z.ZodDefault<z.ZodNumber>;
908
+ expansion_drift: z.ZodDefault<z.ZodNumber>;
909
+ stuck_on_test: z.ZodDefault<z.ZodNumber>;
910
+ context_thrash: z.ZodDefault<z.ZodNumber>;
911
+ }, z.core.$strip>>;
912
+ max_trajectory_lines: z.ZodDefault<z.ZodNumber>;
913
+ escalation_enabled: z.ZodDefault<z.ZodBoolean>;
914
+ detection_timeout_ms: z.ZodDefault<z.ZodNumber>;
915
+ }, z.core.$strip>>;
889
916
  council: z.ZodOptional<z.ZodObject<{
890
917
  enabled: z.ZodDefault<z.ZodBoolean>;
891
918
  maxRounds: z.ZodDefault<z.ZodNumber>;
@@ -12,11 +12,16 @@ export interface TrajectoryConfig {
12
12
  max_lines: number;
13
13
  }
14
14
  export interface TrajectoryEntry {
15
+ step: number;
16
+ agent: string;
17
+ action: string;
18
+ target: string;
19
+ intent: string;
20
+ timestamp: string;
21
+ result: 'success' | 'failure' | 'pending';
15
22
  tool: string;
16
23
  args_summary: string;
17
24
  verdict: string;
18
- timestamp: string;
19
- agent: string;
20
25
  elapsed_ms: number;
21
26
  }
22
27
  /**
@@ -46,6 +51,13 @@ export declare function createTrajectoryLoggerHook(config: Partial<TrajectoryCon
46
51
  metadata: unknown;
47
52
  }) => Promise<void>;
48
53
  };
54
+ /**
55
+ * Resets the step counter for a session. Called when a new session starts
56
+ * or when trajectory tracking should restart from step 1.
57
+ *
58
+ * @param sessionId - Session identifier
59
+ */
60
+ export declare function resetTrajectoryStep(sessionId: string): void;
49
61
  /**
50
62
  * Records the start time for a tool call (called from toolBefore).
51
63
  * Stored in a module-level Map for correlation with toolAfter.