@oh-my-pi/swarm-extension 13.3.6 → 13.3.8

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
@@ -80,7 +80,7 @@ swarm:
80
80
  workspace: ./workspace # Working directory (relative to YAML file location)
81
81
  mode: pipeline # pipeline | parallel | sequential
82
82
  target_count: 10 # Iterations (pipeline mode only, default: 1)
83
- model: claude-opus-4-6 # Model for all agents (optional)
83
+ model: claude-opus-4-6 # Default model for agents without an override (optional)
84
84
 
85
85
  agents:
86
86
  first_agent:
@@ -93,6 +93,7 @@ swarm:
93
93
  - downstream_agent
94
94
  waits_for:
95
95
  - upstream_agent
96
+ model: claude-sonnet-4-5 # Optional per-agent override
96
97
  ```
97
98
 
98
99
  ### Top-Level Fields
@@ -103,7 +104,7 @@ swarm:
103
104
  | `workspace` | yes | — | Shared working directory. Relative paths resolve from YAML file location |
104
105
  | `mode` | no | `sequential` | Execution mode (see below) |
105
106
  | `target_count` | no | `1` | How many times to repeat the full pipeline. Only meaningful in `pipeline` mode |
106
- | `model` | no | session default | Model ID for all agents. Any omp-configured model works |
107
+ | `model` | no | session default | Default model for agents that do not set `agents.<name>.model` |
107
108
 
108
109
  ### Agent Fields
109
110
 
@@ -112,6 +113,7 @@ swarm:
112
113
  | `role` | yes | Short role identifier — becomes the agent's system prompt |
113
114
  | `task` | yes | Complete instructions sent as user prompt. Use YAML `\|` for multi-line |
114
115
  | `extra_context` | no | Additional text appended to system prompt |
116
+ | `model` | no | Model override for this agent only |
115
117
  | `reports_to` | no | List of agent names that depend on this agent |
116
118
  | `waits_for` | no | List of agent names this agent depends on |
117
119
 
@@ -434,14 +436,24 @@ tracking/status.json -> Cumulative state
434
436
 
435
437
  ## Models
436
438
 
437
- Any model configured in omp works. Set it in the YAML:
439
+ Any model configured in omp works. Set a swarm default and optionally override per agent:
438
440
 
439
441
  ```yaml
440
442
  swarm:
441
443
  model: claude-opus-4-6
444
+ agents:
445
+ writer:
446
+ role: technical-writer
447
+ task: |
448
+ Write the draft.
449
+ reviewer:
450
+ role: reviewer
451
+ model: claude-sonnet-4-5
452
+ task: |
453
+ Review the draft.
442
454
  ```
443
455
 
444
- Or omit `model` to use your session's default. Check `packages/ai/src/models.json` for available model IDs.
456
+ Precedence: `agents.<name>.model` `swarm.model` session default. Check `packages/ai/src/models.json` for available model IDs.
445
457
 
446
458
  ---
447
459
 
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "type": "module",
3
3
  "name": "@oh-my-pi/swarm-extension",
4
- "version": "13.3.6",
4
+ "version": "13.3.8",
5
5
  "description": "Swarm orchestration extension for omp",
6
6
  "homepage": "https://github.com/can1357/oh-my-pi",
7
7
  "author": "Derek Rynd",
@@ -164,7 +164,7 @@ export class PipelineController {
164
164
  workspace: options.workspace,
165
165
  swarmName: this.#def.name,
166
166
  iteration,
167
- modelOverride: this.#def.model,
167
+ modelOverride: agent.model ?? this.#def.model,
168
168
  signal: options.signal,
169
169
  onProgress: (_name, _progress) => {
170
170
  options.emitProgress(waveIdx);
@@ -8,6 +8,7 @@ interface RawSwarmAgentConfig {
8
8
  extra_context?: string;
9
9
  reports_to?: string[];
10
10
  waits_for?: string[];
11
+ model?: string;
11
12
  }
12
13
 
13
14
  interface RawSwarmConfig {
@@ -32,6 +33,7 @@ export interface SwarmAgent {
32
33
  extraContext?: string;
33
34
  reportsTo: string[];
34
35
  waitsFor: string[];
36
+ model?: string;
35
37
  }
36
38
 
37
39
  export interface SwarmDefinition {
@@ -95,6 +97,7 @@ export function parseSwarmYaml(content: string): SwarmDefinition {
95
97
  task: config.task.trim(),
96
98
  extraContext: config.extra_context?.trim(),
97
99
  reportsTo: Array.isArray(config.reports_to) ? config.reports_to : [],
100
+ model: typeof config.model === "string" ? config.model.trim() : undefined,
98
101
  waitsFor: Array.isArray(config.waits_for) ? config.waits_for : [],
99
102
  });
100
103
  }
@@ -104,7 +107,7 @@ export function parseSwarmYaml(content: string): SwarmDefinition {
104
107
  workspace: swarm.workspace,
105
108
  mode: mode as SwarmMode,
106
109
  targetCount: swarm.target_count ?? 1,
107
- model: swarm.model,
110
+ model: typeof swarm.model === "string" ? swarm.model.trim() : undefined,
108
111
  agents,
109
112
  agentOrder,
110
113
  };
@@ -118,6 +121,9 @@ export function validateSwarmDefinition(def: SwarmDefinition): string[] {
118
121
  const errors: string[] = [];
119
122
  const agentNames = new Set(def.agents.keys());
120
123
 
124
+ if (def.model !== undefined && def.model.length === 0) {
125
+ errors.push("swarm.model must not be empty when provided");
126
+ }
121
127
  for (const [name, agent] of def.agents) {
122
128
  for (const dep of agent.waitsFor) {
123
129
  if (!agentNames.has(dep)) {
@@ -135,6 +141,9 @@ export function validateSwarmDefinition(def: SwarmDefinition): string[] {
135
141
  errors.push(`Agent '${name}' cannot report to itself`);
136
142
  }
137
143
  }
144
+ if (agent.model !== undefined && agent.model.length === 0) {
145
+ errors.push(`Agent '${name}' model must not be empty when provided`);
146
+ }
138
147
  }
139
148
 
140
149
  if (def.targetCount < 1) {