Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
39 changes: 39 additions & 0 deletions .changeset/add-synthetic-provider.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
---
"opencode-swarm-plugin": minor
---

## 🐝 Add Synthetic LLM Provider Support

Adds support for **Synthetic** as a first-class LLM provider in swarm-tools.

**New Models Available:**

**Coordinator Models (Complex Tasks):**
- `synthetic/hf:moonshotai/Kimi-K2.5` - Strong reasoning model
- `synthetic/hf:deepseek-ai/DeepSeek-V3.2` - Advanced reasoning

**Worker Models (Parallel Tasks):**
- `synthetic/hf:moonshotai/Kimi-K2.5` - Strong reasoning
- `synthetic/hf:MiniMaxAI/MiniMax-M2.1` - Fast and cost-effective
- `synthetic/hf:Qwen/Qwen3-Coder-480B-A35B-Instruct` - Powerful coding model

**Lite Models (Docs, Tests, Simple Edits):**
- `synthetic/hf:MiniMaxAI/MiniMax-M2.1` - Fast and cost-effective
- `synthetic/hf:Qwen/Qwen3-Coder-480B-A35B-Instruct` - Powerful coding model

**Why it matters:**
- Synthetic provides OpenAI-compatible API at `https://api.synthetic.new/openai/v1`
- Enables users already configured with Synthetic in OpenCode to use swarm-tools
- Cost-effective alternative for multi-agent workflows
- Qwen3-Coder specialized for coding tasks

**Usage:**
```bash
swarm setup # Select Synthetic models during setup
```

**Requirements:**
- Synthetic API access configured in OpenCode
- No additional configuration needed in swarm-tools

Refs: #148, #150
24 changes: 9 additions & 15 deletions bun.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

62 changes: 62 additions & 0 deletions packages/opencode-swarm-plugin/bin/swarm.ts
Original file line number Diff line number Diff line change
Expand Up @@ -313,6 +313,7 @@ interface ModelOption {
hint: string;
}

/** Available coordinator models for orchestration and planning tasks */
const COORDINATOR_MODELS: ModelOption[] = [
{
value: "anthropic/claude-sonnet-4-5",
Expand All @@ -339,8 +340,19 @@ const COORDINATOR_MODELS: ModelOption[] = [
label: "Gemini 1.5 Pro",
hint: "More capable, larger context",
},
{
value: "synthetic/hf:moonshotai/Kimi-K2.5",
label: "Synthetic Kimi K2.5",
hint: "Strong reasoning model via Synthetic",
},
{
value: "synthetic/hf:deepseek-ai/DeepSeek-V3.2",
label: "Synthetic DeepSeek V3.2",
hint: "Advanced reasoning via Synthetic",
},
];

/** Available worker models for parallel task execution */
const WORKER_MODELS: ModelOption[] = [
{
value: "anthropic/claude-haiku-4-5",
Expand All @@ -362,6 +374,21 @@ const WORKER_MODELS: ModelOption[] = [
label: "Gemini 2.0 Flash",
hint: "Fast and capable",
},
{
value: "synthetic/hf:moonshotai/Kimi-K2.5",
label: "Synthetic Kimi K2.5",
hint: "Strong reasoning via Synthetic",
},
{
value: "synthetic/hf:MiniMaxAI/MiniMax-M2.1",
label: "Synthetic MiniMax M2.1",
hint: "Fast and cost-effective via Synthetic",
},
{
value: "synthetic/hf:Qwen/Qwen3-Coder-480B-A35B-Instruct",
label: "Synthetic Qwen3 Coder 480B",
hint: "Powerful coding model via Synthetic",
},
];

// ============================================================================
Expand Down Expand Up @@ -2419,6 +2446,16 @@ async function setup(forceReinstall = false, nonInteractive = false) {
label: "Gemini 1.5 Pro",
hint: "More capable",
},
{
value: "synthetic/hf:moonshotai/Kimi-K2.5",
label: "Synthetic Kimi K2.5",
hint: "Strong reasoning model via Synthetic",
},
{
value: "synthetic/hf:deepseek-ai/DeepSeek-V3.2",
label: "Synthetic DeepSeek V3.2",
hint: "Advanced reasoning via Synthetic",
},
],
initialValue: DEFAULT_COORDINATOR,
});
Expand Down Expand Up @@ -2467,6 +2504,21 @@ async function setup(forceReinstall = false, nonInteractive = false) {
label: "Gemini 1.5 Pro",
hint: "More capable",
},
{
value: "synthetic/hf:moonshotai/Kimi-K2.5",
label: "Synthetic Kimi K2.5",
hint: "Strong reasoning via Synthetic",
},
{
value: "synthetic/hf:MiniMaxAI/MiniMax-M2.1",
label: "Synthetic MiniMax M2.1",
hint: "Fast and cost-effective via Synthetic",
},
{
value: "synthetic/hf:Qwen/Qwen3-Coder-480B-A35B-Instruct",
label: "Synthetic Qwen3 Coder 480B",
hint: "Powerful coding model via Synthetic",
},
],
initialValue: DEFAULT_WORKER,
});
Expand Down Expand Up @@ -2501,6 +2553,16 @@ async function setup(forceReinstall = false, nonInteractive = false) {
label: "Gemini 2.0 Flash",
hint: "Fast and capable",
},
{
value: "synthetic/hf:MiniMaxAI/MiniMax-M2.1",
label: "Synthetic MiniMax M2.1",
hint: "Fast and cost-effective via Synthetic",
},
{
value: "synthetic/hf:Qwen/Qwen3-Coder-480B-A35B-Instruct",
label: "Synthetic Qwen3 Coder 480B",
hint: "Powerful coding model via Synthetic",
},
],
initialValue: DEFAULT_LITE,
});
Expand Down
39 changes: 39 additions & 0 deletions packages/opencode-swarm-plugin/src/model-selection.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -185,4 +185,43 @@ describe("selectWorkerModel", () => {
const result = selectWorkerModel(subtask, mockConfig);
expect(result).toBe("anthropic/claude-haiku-4-5");
});

test("uses Synthetic model when explicitly provided", () => {
const subtask: DecomposedSubtask & { model?: string } = {
title: "Complex reasoning task",
description: "Use advanced reasoning",
files: ["src/ai.ts"],
estimated_effort: "large",
model: "synthetic/hf:moonshotai/Kimi-K2.5",
};

const result = selectWorkerModel(subtask, mockConfig);
expect(result).toBe("synthetic/hf:moonshotai/Kimi-K2.5");
});

test("synthetic DeepSeek model is selectable", () => {
const subtask: DecomposedSubtask & { model?: string } = {
title: "Deep reasoning task",
description: "Deep analysis required",
files: ["src/deep.ts"],
estimated_effort: "large",
model: "synthetic/hf:deepseek-ai/DeepSeek-V3.2",
};

const result = selectWorkerModel(subtask, mockConfig);
expect(result).toBe("synthetic/hf:deepseek-ai/DeepSeek-V3.2");
});

test("synthetic MiniMax model is selectable for worker tasks", () => {
const subtask: DecomposedSubtask & { model?: string } = {
title: "Fast processing task",
description: "Process data quickly",
files: ["src/process.ts"],
estimated_effort: "small",
model: "synthetic/hf:MiniMaxAI/MiniMax-M2.1",
};

const result = selectWorkerModel(subtask, mockConfig);
expect(result).toBe("synthetic/hf:MiniMaxAI/MiniMax-M2.1");
});
});