opencode-async-agent 1.0.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/AGENTS.md +119 -0
- package/README.md +151 -0
- package/package.json +10 -0
- package/src/plugin/manager.ts +630 -0
- package/src/plugin/plugin.ts +200 -0
- package/src/plugin/rules.ts +115 -0
- package/src/plugin/tools.ts +230 -0
- package/src/plugin/types.ts +80 -0
- package/src/plugin/utils.ts +51 -0
package/AGENTS.md
ADDED
|
@@ -0,0 +1,119 @@
|
|
|
1
|
+
# AGENTS.md — opencode-async-agent
|
|
2
|
+
|
|
3
|
+
## What This Is
|
|
4
|
+
|
|
5
|
+
OpenCode plugin providing async background delegation. TypeScript source in `src/plugin/`, bundled via esbuild to `dist/async-agent.js`. No test framework. No linter configured.
|
|
6
|
+
|
|
7
|
+
## Build
|
|
8
|
+
|
|
9
|
+
```bash
|
|
10
|
+
# Install deps
|
|
11
|
+
npm install
|
|
12
|
+
|
|
13
|
+
# Build
|
|
14
|
+
npm run build
|
|
15
|
+
|
|
16
|
+
# Verify build worked
|
|
17
|
+
ls -la dist/async-agent.js
|
|
18
|
+
```
|
|
19
|
+
|
|
20
|
+
## Project Structure
|
|
21
|
+
|
|
22
|
+
```
|
|
23
|
+
src/plugin/
|
|
24
|
+
plugin.ts — Entry point. Registers tools, hooks, slash commands, events
|
|
25
|
+
manager.ts — DelegationManager class. Core state machine for delegations
|
|
26
|
+
tools.ts — Tool factories (delegate, read, list, cancel, resume)
|
|
27
|
+
types.ts — All interfaces and type definitions
|
|
28
|
+
rules.ts — System prompt injection + compaction context
|
|
29
|
+
utils.ts — Logger, toast, formatDuration helpers
|
|
30
|
+
dist/
|
|
31
|
+
async-agent.js — Bundled output (committed)
|
|
32
|
+
```
|
|
33
|
+
|
|
34
|
+
## Code Style
|
|
35
|
+
|
|
36
|
+
### TypeScript
|
|
37
|
+
- Strict types, no `any` except when casting OpenCode client for optional APIs
|
|
38
|
+
- Use `type` imports: `import type { Foo } from "./types"`
|
|
39
|
+
- Tabs for indentation, no semicolons (except rare cases)
|
|
40
|
+
- Double quotes for strings
|
|
41
|
+
- Interfaces over type aliases for object shapes
|
|
42
|
+
|
|
43
|
+
### Naming
|
|
44
|
+
- PascalCase: classes (`DelegationManager`), interfaces (`Delegation`, `DelegateInput`)
|
|
45
|
+
- camelCase: functions (`createDelegate`), variables, methods
|
|
46
|
+
- UPPER_SNAKE: constants (`MAX_RUN_TIME_MS`, `DELEGATION_RULES`)
|
|
47
|
+
- Slash command names: kebab-case strings (`"delegation"`)
|
|
48
|
+
|
|
49
|
+
### Imports
|
|
50
|
+
- Group order: external packages → local types → local modules
|
|
51
|
+
- Always use relative paths (`"./types"`, `"./manager"`)
|
|
52
|
+
- External deps are `@opencode-ai/plugin` and `@opencode-ai/sdk` only
|
|
53
|
+
|
|
54
|
+
### Functions
|
|
55
|
+
- Tool creators follow factory pattern: `createXxx(manager) → tool({...})`
|
|
56
|
+
- Tools return `string` (success message or error text), never throw to caller
|
|
57
|
+
- Prefix user-facing errors with `❌`
|
|
58
|
+
- Manager methods are `async` and return typed results
|
|
59
|
+
|
|
60
|
+
### Error Handling
|
|
61
|
+
- Tools: try/catch → return error string (never throw)
|
|
62
|
+
- Async fire-and-forget: `.catch(() => {})` on non-critical promises (logging, toasts)
|
|
63
|
+
- Manager notifications: catch and log, never crash the plugin
|
|
64
|
+
- SDK calls that might fail: wrap in try/catch, ignore or log
|
|
65
|
+
|
|
66
|
+
### Plugin Hooks Pattern
|
|
67
|
+
- `config` hook → register slash commands via `input.command[name] = { template, description }`
|
|
68
|
+
- `command.execute.before` hook → handle slash command, throw Error to signal "handled"
|
|
69
|
+
- `event` hook → listen for `session.idle`, `session.deleted` etc.
|
|
70
|
+
- `experimental.chat.system.transform` → inject into system prompt
|
|
71
|
+
- `experimental.session.compacting` → inject context during compaction
|
|
72
|
+
|
|
73
|
+
### State Management
|
|
74
|
+
- All state in `DelegationManager.delegations: Map<string, Delegation>`
|
|
75
|
+
- In-memory only, no persistence to disk
|
|
76
|
+
- Delegation ID = OpenCode session ID (same value)
|
|
77
|
+
- Status flow: `running` → `completed` | `error` | `cancelled` | `timeout`
|
|
78
|
+
|
|
79
|
+
## Key Patterns
|
|
80
|
+
|
|
81
|
+
### Adding a new tool
|
|
82
|
+
1. Define args interface in `tools.ts`
|
|
83
|
+
2. Create factory function `createXxx(manager)` returning `tool({...})`
|
|
84
|
+
3. Register in `plugin.ts` under the `tool:` object
|
|
85
|
+
4. Add any needed manager methods in `manager.ts`
|
|
86
|
+
5. Rebuild
|
|
87
|
+
|
|
88
|
+
### Adding a new slash command
|
|
89
|
+
1. Define command name constant in `plugin.ts`
|
|
90
|
+
2. Register in `config` hook: `input.command[name] = { template, description }`
|
|
91
|
+
3. Handle in `command.execute.before` hook, throw Error when handled
|
|
92
|
+
4. Send output via `client.session.prompt({ path: { id: sessionID }, body: { noReply: true, parts: [...] } })`
|
|
93
|
+
|
|
94
|
+
### Tool execute signature
|
|
95
|
+
```typescript
|
|
96
|
+
async execute(args: ArgsType, toolCtx: ToolContext): Promise<string>
|
|
97
|
+
```
|
|
98
|
+
- `toolCtx.sessionID` — current chat session
|
|
99
|
+
- `toolCtx.messageID` — current message
|
|
100
|
+
- `toolCtx.agent` — current agent name
|
|
101
|
+
- Always guard: `if (!toolCtx?.sessionID) return "❌ ..."`
|
|
102
|
+
|
|
103
|
+
## External Dependencies
|
|
104
|
+
|
|
105
|
+
- `@opencode-ai/plugin` — tool() factory, ToolContext, Plugin type (external, not bundled)
|
|
106
|
+
- `@opencode-ai/sdk` — OpenCode client types, Event, Message, Part (external, not bundled)
|
|
107
|
+
- `esbuild` — build tool (devDependency)
|
|
108
|
+
|
|
109
|
+
## No Tests
|
|
110
|
+
|
|
111
|
+
No test framework is configured. Validate changes by building and running in OpenCode.
|
|
112
|
+
|
|
113
|
+
## Common Gotchas
|
|
114
|
+
|
|
115
|
+
- `dist/` is committed — always rebuild after changes
|
|
116
|
+
- `@opencode-ai/*` packages are marked external in esbuild — they're provided by the OpenCode runtime
|
|
117
|
+
- Delegation ID and session ID are the same value (kept as two fields for clarity)
|
|
118
|
+
- `noReply: true` on prompts means "show to user but don't trigger AI response"
|
|
119
|
+
- Throwing in `command.execute.before` signals the command was handled by this plugin
|
package/README.md
ADDED
|
@@ -0,0 +1,151 @@
|
|
|
1
|
+
# OpenCode Async Agent Plugin
|
|
2
|
+
|
|
3
|
+
Async background delegation for OpenCode — run multiple AI agents in parallel.
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
## Features
|
|
7
|
+
|
|
8
|
+
- **Parallel Execution** — Delegate tasks to background agents while you continue working
|
|
9
|
+
- **Multiple Agents** — Use explore, researcher, or any custom agent
|
|
10
|
+
- **Model Override** — Specify which model runs each task (e.g., `minimax/MiniMax-M2.5`)
|
|
11
|
+
- **Session Persistence** — Resume cancelled tasks without losing context
|
|
12
|
+
- **Slash Commands** — `/delegation` to list all delegation status and metadata
|
|
13
|
+
- **System Prompt Injection** — Your `~/.config/opencode/async-agent.md` config is automatically loaded
|
|
14
|
+
|
|
15
|
+
## Installation
|
|
16
|
+
|
|
17
|
+
### Manual Setup (Current)
|
|
18
|
+
|
|
19
|
+
1. **Clone and build:**
|
|
20
|
+
```bash
|
|
21
|
+
git clone https://github.com/aptdnfapt/opencode-async-agent
|
|
22
|
+
cd opencode-async-agent
|
|
23
|
+
npm install
|
|
24
|
+
npm run build
|
|
25
|
+
```
|
|
26
|
+
|
|
27
|
+
2. **Copy to OpenCode plugins:**
|
|
28
|
+
```bash
|
|
29
|
+
mkdir -p ~/.config/opencode/plugin
|
|
30
|
+
cp dist/async-agent.js ~/.config/opencode/plugin/
|
|
31
|
+
```
|
|
32
|
+
|
|
33
|
+
3. **Restart OpenCode** — the plugin auto-registers on startup
|
|
34
|
+
|
|
35
|
+
### NPM Package (Coming Soon)
|
|
36
|
+
|
|
37
|
+
```bash
|
|
38
|
+
npm install -g oc-async-agent
|
|
39
|
+
```
|
|
40
|
+
|
|
41
|
+
## Usage
|
|
42
|
+
|
|
43
|
+
The plugin adds these tools to your OpenCode agent:
|
|
44
|
+
|
|
45
|
+
| Tool | Description |
|
|
46
|
+
|------|-------------|
|
|
47
|
+
| `delegate(prompt, agent)` | Start a background task |
|
|
48
|
+
| `delegate(prompt, agent, model)` | Start with specific model |
|
|
49
|
+
| `delegation_read(id)` | Get completed result |
|
|
50
|
+
| `delegation_list()` | List active/completed tasks |
|
|
51
|
+
| `delegation_cancel(id\|all)` | Cancel running task(s) |
|
|
52
|
+
| `delegation_resume(id, prompt?)` | Resume cancelled task |
|
|
53
|
+
|
|
54
|
+
### Slash Commands
|
|
55
|
+
|
|
56
|
+
**`/delegation`** — List all active and completed delegations for the current session, including:
|
|
57
|
+
- Delegation ID (with `opencode -s {id}` command to open session)
|
|
58
|
+
- Status (running/completed/error/cancelled)
|
|
59
|
+
- Agent used
|
|
60
|
+
- Duration
|
|
61
|
+
- Start time
|
|
62
|
+
- Title/description
|
|
63
|
+
|
|
64
|
+
## Configuration
|
|
65
|
+
|
|
66
|
+
### Step 1: Find Model Names
|
|
67
|
+
|
|
68
|
+
First, run this command to see available models and get the full `provider/model` string:
|
|
69
|
+
|
|
70
|
+
```bash
|
|
71
|
+
opencode models | grep <model-name>
|
|
72
|
+
```
|
|
73
|
+
|
|
74
|
+
For example:
|
|
75
|
+
```bash
|
|
76
|
+
opencode models | grep minimax
|
|
77
|
+
# Output: minimax/MiniMax-M2.5
|
|
78
|
+
# minimax/MiniMax-M2.1
|
|
79
|
+
```
|
|
80
|
+
|
|
81
|
+
### Step 2: Configure Models
|
|
82
|
+
|
|
83
|
+
**Recommended:** Create `~/.config/opencode/async-agent.md`:
|
|
84
|
+
|
|
85
|
+
```markdown
|
|
86
|
+
# Async Agent Model Configuration
|
|
87
|
+
|
|
88
|
+
## Recommended Models
|
|
89
|
+
|
|
90
|
+
### Fast
|
|
91
|
+
- `minimax/MiniMax-M2.5`
|
|
92
|
+
|
|
93
|
+
### Good Understanding
|
|
94
|
+
- `synthetic/hf:moonshotai/Kimi-K2.5`
|
|
95
|
+
|
|
96
|
+
## Notes
|
|
97
|
+
Format: `provider/model` — pass to `delegate()` via the `model` parameter.
|
|
98
|
+
```
|
|
99
|
+
|
|
100
|
+
This file is automatically injected into your agent's system prompt, so it knows which models to use when you ask it to delegate tasks.
|
|
101
|
+
|
|
102
|
+
**Alternative:** Create subagent markdown files with hardcoded models. Learn more at [Agents Documentation](https://opencode.ai/docs/agents/#markdown)
|
|
103
|
+
|
|
104
|
+
## How I Use It
|
|
105
|
+
|
|
106
|
+
My workflow with async agent goes like this:
|
|
107
|
+
|
|
108
|
+
1. **Use Claude Opus 4.5 as my main planner** — I tell Opus what I want to build, including tech stack, key libraries, APIs, etc.
|
|
109
|
+
|
|
110
|
+
2. **Identify knowledge gaps** — When I don't know much about a specific component or tech choice
|
|
111
|
+
|
|
112
|
+
3. **Launch parallel research** — I tell Opus: "Send 15 minimax agents to research this part"
|
|
113
|
+
|
|
114
|
+
Opus then makes multiple `delegate()` tool calls with:
|
|
115
|
+
```
|
|
116
|
+
delegate(prompt="Research React patterns for large apps", agent="explore", model="minimax/MiniMax-M2.5")
|
|
117
|
+
```
|
|
118
|
+
- Each delegation is a separate session owned by the main session
|
|
119
|
+
- Agents perform research using web search, zread/zai for GitHub, grep.app for code examples, MCP tools, or cloned OSS codebases
|
|
120
|
+
|
|
121
|
+
4. **Continue planning while research runs** — Opus keeps working with me on the plan while the async agents investigate in the background
|
|
122
|
+
|
|
123
|
+
5. **Check live progress** — To see what a delegation is doing in real-time:
|
|
124
|
+
- Press `Ctrl+X` then `←` / `→` to navigate sessions
|
|
125
|
+
- Child sessions appear under parent (owned by main agent)
|
|
126
|
+
- You can watch the agent work live
|
|
127
|
+
|
|
128
|
+
6. **Get notified + read results** — When research completes, `<system-reminder>` fires to notify Opus, Opus reads the results internally with `delegation_read(id)`, then explains the findings to me
|
|
129
|
+
|
|
130
|
+
The parallelism is key — 15 agents researching different aspects simultaneously means comprehensive information in the time it would take to do one sequential query.
|
|
131
|
+
|
|
132
|
+
**Note:** I've also tried using async agent for parallel feature implementation but haven't found good success with that.
|
|
133
|
+
|
|
134
|
+
|
|
135
|
+
## Project Structure
|
|
136
|
+
|
|
137
|
+
```
|
|
138
|
+
src/plugin/
|
|
139
|
+
plugin.ts — Entry point, tool registration
|
|
140
|
+
manager.ts — Delegation state machine
|
|
141
|
+
tools.ts — Tool factories
|
|
142
|
+
types.ts — Type definitions
|
|
143
|
+
rules.ts — System prompt injection
|
|
144
|
+
utils.ts — Helpers
|
|
145
|
+
dist/
|
|
146
|
+
async-agent.js — Bundled output
|
|
147
|
+
```
|
|
148
|
+
|
|
149
|
+
## License
|
|
150
|
+
|
|
151
|
+
MIT
|
package/package.json
ADDED
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "opencode-async-agent",
|
|
3
|
+
"version": "1.0.0",
|
|
4
|
+
"scripts": {
|
|
5
|
+
"build": "esbuild src/plugin/plugin.ts --bundle --format=esm --platform=node --outfile=dist/async-agent.js --external:@opencode-ai/plugin --external:@opencode-ai/sdk"
|
|
6
|
+
},
|
|
7
|
+
"devDependencies": {
|
|
8
|
+
"esbuild": "^0.27.3"
|
|
9
|
+
}
|
|
10
|
+
}
|