opencode-titan 0.1.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/LICENSE +21 -0
- package/README.md +257 -0
- package/dist/agents/index.d.ts +19 -0
- package/dist/agents/myrmidon.d.ts +8 -0
- package/dist/agents/titan.d.ts +17 -0
- package/dist/config/constants.d.ts +21 -0
- package/dist/config/index.d.ts +5 -0
- package/dist/config/loader.d.ts +21 -0
- package/dist/config/providers.d.ts +46 -0
- package/dist/config/schema.d.ts +98 -0
- package/dist/index.d.ts +4 -0
- package/dist/index.js +852 -0
- package/dist/utils/provider-lock.d.ts +45 -0
- package/opencode-titan.schema.json +120 -0
- package/package.json +65 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Zack Duford
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.md
ADDED
|
@@ -0,0 +1,257 @@
|
|
|
1
|
+
<div align="center">
|
|
2
|
+
<h3>⚡ opencode-titan ⚡</h3>
|
|
3
|
+
|
|
4
|
+
<p><i>One mind that never touches the keyboard. A fleet of hands that never stops moving.<br>Plan with the slow, expensive genius, and let the fast ones build in parallel.</i></p>
|
|
5
|
+
|
|
6
|
+
<p><b>OpenCode Orchestration Plugin</b> · Mix any models · Delegate everything · Run in parallel</p>
|
|
7
|
+
|
|
8
|
+
<p><sub>✦ ✦ ✦</sub></p>
|
|
9
|
+
|
|
10
|
+
</div>
|
|
11
|
+
|
|
12
|
+
## What's This Plugin
|
|
13
|
+
|
|
14
|
+
`opencode-titan` is an agent-orchestration plugin for [OpenCode](https://github.com/sst/opencode). It introduces a **Titan orchestrator** — your most capable (and slowest, most expensive) model — whose only job is to think, plan, and route. Every piece of executable work is handed off to a fleet of faster **Myrmidons** that run in parallel.
|
|
15
|
+
|
|
16
|
+
The core idea is simple: **your smartest model is often your slowest and most expensive one.** Titan is meant to be a frontier heavyweight — something like Opus 5.5, GLM 5.2, or a beast like Nex N2 Pro running on local hardware: far slower and pricier than a typical local model, but far smarter. Instead of letting a model like that grind through file reads, searches, and edits — burning tokens and wall-clock time on grunt work — Titan spends its expensive inference budget only on planning and synthesis, while cheaper, faster Myrmidons do the legwork simultaneously.
|
|
17
|
+
|
|
18
|
+
The result is a workflow that balances **quality, speed, and cost** — deep reasoning where it matters, raw throughput everywhere else.
|
|
19
|
+
|
|
20
|
+
To meet the agents, jump to **[Meet the Agents](#meet-the-agents)**. For setup, see **[Getting Started](#getting-started)**.
|
|
21
|
+
|
|
22
|
+
## How It Works
|
|
23
|
+
|
|
24
|
+
The plugin builds a two-tier hierarchy of agents:
|
|
25
|
+
|
|
26
|
+
- **Titan** dispatches all independent tasks to Myrmidons **in parallel** within a single response turn.
|
|
27
|
+
- **Myrmidons** share model providers, so Myrmidons running **different models** on the same provider are scheduled sequentially — a provider (physical backend) holds only one model in VRAM at a time. A Myrmidon with `maxInstances > 1` is the exception: multiple instances of its *same* model run in parallel on that provider. The plugin detects provider conflicts and warns Titan so it can plan around them.
|
|
28
|
+
- Titan **never** performs work a Myrmidon can handle — it plans, routes, quality-gates, and synthesizes results.
|
|
29
|
+
|
|
30
|
+
> [!TIP]
|
|
31
|
+
> The magic is in the prompt. Titan's system prompt is generated dynamically per session from your configured fleet — it knows each Myrmidon's speed, intelligence, model type, and provider, and delegates accordingly.
|
|
32
|
+
|
|
33
|
+
## Installation
|
|
34
|
+
|
|
35
|
+
> [!NOTE]
|
|
36
|
+
> This plugin is not published to npm yet, so install it manually from source. npm/Bun package installation is coming soon.
|
|
37
|
+
|
|
38
|
+
**1. Clone and build the plugin:**
|
|
39
|
+
|
|
40
|
+
```bash
|
|
41
|
+
git clone https://github.com/DEV-DUFORD/opencode-titan.git
|
|
42
|
+
cd opencode-titan
|
|
43
|
+
bun install
|
|
44
|
+
bun run build
|
|
45
|
+
```
|
|
46
|
+
|
|
47
|
+
This produces the bundled plugin in `dist/`.
|
|
48
|
+
|
|
49
|
+
**2. Register the local build in your OpenCode config** (`opencode.json`).
|
|
50
|
+
|
|
51
|
+
OpenCode treats any plugin entry starting with `.`, `file://`, or an absolute path as a local file plugin, so point it at the cloned directory:
|
|
52
|
+
|
|
53
|
+
```json
|
|
54
|
+
{
|
|
55
|
+
"$schema": "https://opencode.ai/config.json",
|
|
56
|
+
"plugin": ["/absolute/path/to/opencode-titan"]
|
|
57
|
+
}
|
|
58
|
+
```
|
|
59
|
+
|
|
60
|
+
Restart OpenCode and Titan becomes your default agent.
|
|
61
|
+
|
|
62
|
+
## Getting Started
|
|
63
|
+
|
|
64
|
+
1. **Create your plugin config** at `~/.config/opencode/opencode-titan.jsonc`
|
|
65
|
+
|
|
66
|
+
2. **Pick your Titan** — the smartest model you have, even if it's slow and expensive (think Opus 5.5, GLM 5.2, or Nex N2 Pro on local hardware).
|
|
67
|
+
|
|
68
|
+
3. **Assemble your fleet** — one or more Myrmidons, each rated for `speed`, `intelligence`, and `modelType`.
|
|
69
|
+
|
|
70
|
+
4. **Start OpenCode.** Titan becomes the default agent and delegates from there.
|
|
71
|
+
|
|
72
|
+
Here's a complete starting configuration:
|
|
73
|
+
|
|
74
|
+
```jsonc
|
|
75
|
+
{
|
|
76
|
+
// Optional: override Titan's model and settings.
|
|
77
|
+
// Titan should be your most capable model, even if it's slow and expensive.
|
|
78
|
+
"titan": {
|
|
79
|
+
"model": "anthropic/claude-sonnet-4-20250514",
|
|
80
|
+
"temperature": 0.1
|
|
81
|
+
},
|
|
82
|
+
|
|
83
|
+
// Required: at least one Myrmidon.
|
|
84
|
+
// Myrmidons should be fast and cheap — they do the actual work.
|
|
85
|
+
"myrmidons": [
|
|
86
|
+
{
|
|
87
|
+
"model": "openai/gpt-4.1-mini",
|
|
88
|
+
"speed": 9,
|
|
89
|
+
"intelligence": 6,
|
|
90
|
+
"modelType": "sparse",
|
|
91
|
+
"displayName": "Fast Searcher"
|
|
92
|
+
},
|
|
93
|
+
{
|
|
94
|
+
"model": "anthropic/claude-haiku-3.5",
|
|
95
|
+
"speed": 7,
|
|
96
|
+
"intelligence": 8,
|
|
97
|
+
"modelType": "dense"
|
|
98
|
+
}
|
|
99
|
+
]
|
|
100
|
+
}
|
|
101
|
+
```
|
|
102
|
+
|
|
103
|
+
> [!NOTE]
|
|
104
|
+
> The legacy `children` key is still accepted as a deprecated alias for `myrmidons` (and each Myrmidon is also routable under its old `child-N` name), so existing configs keep working. New configs should use `myrmidons`. If both keys are present, `myrmidons` wins.
|
|
105
|
+
|
|
106
|
+
> [!TIP]
|
|
107
|
+
> Mix providers to unlock real parallelism. Two Myrmidons running **different models** on the same provider run one after another; two Myrmidons on *different* providers run at the same time. Set `maxInstances` on a Myrmidon to run several copies of its *same* model in parallel on one provider.
|
|
108
|
+
|
|
109
|
+
## Meet the Agents
|
|
110
|
+
|
|
111
|
+
### 🧠 Titan — The Orchestrator
|
|
112
|
+
|
|
113
|
+
Titan is the most intelligent agent in the fleet, and by far the slowest and most expensive to run. It never reads a file, runs a search, or writes a line of code if a Myrmidon can do it instead. Its entire purpose is strategic: decompose the goal, route each task to the best-suited Myrmidon, gate the quality of what comes back, and synthesize the final result.
|
|
114
|
+
|
|
115
|
+
<table>
|
|
116
|
+
<tr><td><b>Role</b></td><td><code>Planning, routing, quality-gating, and synthesis</code></td></tr>
|
|
117
|
+
<tr><td><b>Prompt</b></td><td><a href="src/agents/titan.ts"><code>titan.ts</code></a> — dynamically built from your fleet</td></tr>
|
|
118
|
+
<tr><td><b>Model Guidance</b></td><td>Choose your strongest reasoning model — an expensive frontier model (Opus 5.5, GLM 5.2) or a heavy local model like Nex N2 Pro. Titan needs judgment and instruction-following, not throughput. Slow and expensive is fine — it delegates the slow, token-hungry parts away.</td></tr>
|
|
119
|
+
</table>
|
|
120
|
+
|
|
121
|
+
### ⚙️ Myrmidons — The Fleet
|
|
122
|
+
|
|
123
|
+
Myrmidons are the hands. Each executes a delegated task and reports back concisely — responses to Titan are enforced to a single paragraph, 500 words max, keeping Titan's context lean. Every Myrmidon declares a `modelType` that shapes how Titan routes work to it:
|
|
124
|
+
|
|
125
|
+
<table>
|
|
126
|
+
<tr>
|
|
127
|
+
<td width="20%" valign="top"><b>🔍 sparse</b></td>
|
|
128
|
+
<td valign="top">Faster models tuned for <b>information gathering</b> — searching the codebase, reading files, collecting context. Route broad reconnaissance here.</td>
|
|
129
|
+
</tr>
|
|
130
|
+
<tr>
|
|
131
|
+
<td width="20%" valign="top"><b>🛠️ dense</b></td>
|
|
132
|
+
<td valign="top">Models tuned for <b>logic and reasoning</b> — implementation, refactors, and tasks that need careful thought. Route the hard thinking here.</td>
|
|
133
|
+
</tr>
|
|
134
|
+
</table>
|
|
135
|
+
|
|
136
|
+
<table>
|
|
137
|
+
<tr><td><b>Role</b></td><td><code>Execute delegated tasks and report back concisely</code></td></tr>
|
|
138
|
+
<tr><td><b>Prompt</b></td><td><a href="src/agents/myrmidon.ts"><code>myrmidon.ts</code></a></td></tr>
|
|
139
|
+
<tr><td><b>Model Guidance</b></td><td>Choose fast, cost-efficient models. Speed and parallelism usually matter more than raw reasoning power here.</td></tr>
|
|
140
|
+
</table>
|
|
141
|
+
|
|
142
|
+
## Configuration
|
|
143
|
+
|
|
144
|
+
### Myrmidon Options
|
|
145
|
+
|
|
146
|
+
| Field | Type | Required | Description |
|
|
147
|
+
|---|---|:---:|---|
|
|
148
|
+
| `model` | `string` | ✅ | Model identifier in `provider/model` format |
|
|
149
|
+
| `speed` | `number` (1–10) | ✅ | Relative speed rating; higher = faster responses |
|
|
150
|
+
| `intelligence` | `number` (1–10) | ✅ | Reasoning capability rating; higher = better logic |
|
|
151
|
+
| `modelType` | `"dense"` \| `"sparse"` | ✅ | `dense` for logic/reasoning, `sparse` for search/info gathering |
|
|
152
|
+
| `maxInstances` | `number` (≥1) | | Max parallel instances Titan may run for this Myrmidon. Since instances share the same model (already in the provider's VRAM), they run concurrently on the same provider. Default: `1` |
|
|
153
|
+
| `temperature` | `number` (0–2) | | Sampling temperature (default: `0.1`) |
|
|
154
|
+
| `variant` | `string` | | Selects a named model variant defined by the provider for this `model` (see [Model variants](#model-variants)). Must match a variant key the provider declares for the model; leave unset to use the model's defaults |
|
|
155
|
+
| `displayName` | `string` | | Friendly name shown in the UI |
|
|
156
|
+
| `provider` | `string` | | Explicit provider name (defaults to the prefix of `model`) |
|
|
157
|
+
|
|
158
|
+
### Titan Options
|
|
159
|
+
|
|
160
|
+
| Field | Type | Description |
|
|
161
|
+
|---|---|---|
|
|
162
|
+
| `model` | `string` | Titan's model in `provider/model` format |
|
|
163
|
+
| `temperature` | `number` (0–2) | Sampling temperature (default: `0.1`) |
|
|
164
|
+
| `variant` | `string` | Selects a named model variant defined by the provider for Titan's `model` (see [Model variants](#model-variants)). Must match a variant key the provider declares for the model; leave unset to use the model's defaults |
|
|
165
|
+
| `prompt` | `string` | Inline custom system prompt (replaces the default entirely) |
|
|
166
|
+
|
|
167
|
+
### Plugin Options
|
|
168
|
+
|
|
169
|
+
| Field | Type | Description |
|
|
170
|
+
|---|---|---|
|
|
171
|
+
| `titan` | `object` | Titan overrides (see above) |
|
|
172
|
+
| `myrmidons` | `array` | The Myrmidon fleet (see above) |
|
|
173
|
+
| `children` | `array` | **Deprecated** alias for `myrmidons`, kept for backwards compatibility. Prefer `myrmidons`; if both are set, `myrmidons` wins |
|
|
174
|
+
| `disabled_tools` | `string[]` | Tool names to disable for the plugin's agents |
|
|
175
|
+
| `backgroundJobs.maxSessionsPerAgent` | `number` (1–10) | Max concurrent sessions per agent (default: `10`) |
|
|
176
|
+
|
|
177
|
+
### Config Locations
|
|
178
|
+
|
|
179
|
+
Config is loaded in two layers — **project settings override user settings** via deep merge:
|
|
180
|
+
|
|
181
|
+
1. **User-level** — searched in `$XDG_CONFIG_HOME/opencode/`, `~/.config/opencode/`, then `~/.opencode/`
|
|
182
|
+
2. **Project-level** — `.opencode/opencode-titan.{json,jsonc}`
|
|
183
|
+
|
|
184
|
+
Both `.json` and `.jsonc` are supported. JSONC files allow comments (`//`, `/* */`) and `{env:VAR_NAME}` environment variable placeholders.
|
|
185
|
+
|
|
186
|
+
### Model variants
|
|
187
|
+
|
|
188
|
+
`variant` (available on both Myrmidons and Titan) selects a **named model preset** that the *provider* defines for a given model — it does **not** change which model runs (that's `model`). Think of it as: `model` picks the model, `variant` picks a named configuration of that model.
|
|
189
|
+
|
|
190
|
+
How it works in OpenCode:
|
|
191
|
+
|
|
192
|
+
1. **The provider defines variants.** In your OpenCode provider/model config, a model can declare a `variants` map — a set of named presets (e.g. a reasoning/`thinking` mode, a `fast` mode), each with its own overrides.
|
|
193
|
+
2. **The agent selects one by name.** Setting `variant: "thinking"` on an agent tells OpenCode to run that model using its `thinking` variant.
|
|
194
|
+
|
|
195
|
+
Notes:
|
|
196
|
+
|
|
197
|
+
- The value is **not free-form** — it must match a variant key the provider declares for that specific model. If the model has no matching variant, OpenCode has nothing to resolve it against.
|
|
198
|
+
- **Leave `variant` unset** to run the model with its default settings. Most setups don't need it.
|
|
199
|
+
|
|
200
|
+
### Custom Prompts
|
|
201
|
+
|
|
202
|
+
Drop prompt files alongside your config to override or extend an agent's system prompt:
|
|
203
|
+
|
|
204
|
+
| File | Effect |
|
|
205
|
+
|---|---|
|
|
206
|
+
| `titan.md` | **Replaces** Titan's default system prompt entirely |
|
|
207
|
+
| `titan_append.md` | **Appends** to the end of Titan's system prompt |
|
|
208
|
+
|
|
209
|
+
Search locations:
|
|
210
|
+
|
|
211
|
+
- **User-level:** `~/.config/opencode/opencode-titan/titan.md`
|
|
212
|
+
- **Project-level:** `.opencode/opencode-titan/titan.md`
|
|
213
|
+
|
|
214
|
+
## Architecture
|
|
215
|
+
|
|
216
|
+
```
|
|
217
|
+
src/
|
|
218
|
+
├── index.ts # Plugin entry — registers agents, hooks, and events
|
|
219
|
+
├── agents/
|
|
220
|
+
│ ├── index.ts # Agent factory — creates Titan + N Myrmidons
|
|
221
|
+
│ ├── titan.ts # Titan prompt builder with dynamic Myrmidon descriptions
|
|
222
|
+
│ └── myrmidon.ts # Myrmidon factory with context-budget constraints
|
|
223
|
+
├── config/
|
|
224
|
+
│ ├── index.ts # Config exports
|
|
225
|
+
│ ├── schema.ts # Zod schemas for all config types
|
|
226
|
+
│ ├── loader.ts # Config loading — JSONC parsing, env vars, deep merge
|
|
227
|
+
│ ├── providers.ts # Provider resolution helpers
|
|
228
|
+
│ └── constants.ts # Agent names, delegation reminders
|
|
229
|
+
└── utils/
|
|
230
|
+
└── provider-lock.ts # Model-scoped per-provider scheduling lock
|
|
231
|
+
```
|
|
232
|
+
|
|
233
|
+
The plugin registers hooks in `src/index.ts` to wire everything into OpenCode:
|
|
234
|
+
|
|
235
|
+
| Hook | Purpose |
|
|
236
|
+
|------|---------|
|
|
237
|
+
| `agent` | Returns the agents record (Titan + Myrmidons) for OpenCode to register |
|
|
238
|
+
| `config` | Sets Titan as the default agent and merges plugin agents into the config |
|
|
239
|
+
| `chat.message` | Tracks which agent is active per session |
|
|
240
|
+
| `experimental.chat.system.transform` | Injects the delegation reminder into Titan's prompt at runtime |
|
|
241
|
+
| `event` | Cleans up session state on `session.deleted` |
|
|
242
|
+
|
|
243
|
+
## Development
|
|
244
|
+
|
|
245
|
+
```bash
|
|
246
|
+
bun run build # Build to dist/
|
|
247
|
+
bun run typecheck # TypeScript type checking
|
|
248
|
+
bun run lint # Biome linter
|
|
249
|
+
bun run format # Biome formatter
|
|
250
|
+
bun run check:ci # Lint and format (CI mode)
|
|
251
|
+
```
|
|
252
|
+
|
|
253
|
+
Built with TypeScript, bundled to ESM with esbuild, validated with Zod, and linted/formatted with Biome (80-char lines, 2-space indent, single quotes, trailing commas).
|
|
254
|
+
|
|
255
|
+
## License
|
|
256
|
+
|
|
257
|
+
MIT
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import type { AgentConfig as SDKAgentConfig } from '@opencode-ai/sdk/v2';
|
|
2
|
+
import { type PluginConfig } from '../config';
|
|
3
|
+
import { type AgentDefinition } from './titan';
|
|
4
|
+
/**
|
|
5
|
+
* Create all agent definitions: Titan + N Myrmidons.
|
|
6
|
+
*
|
|
7
|
+
* Each Myrmidon is also registered under its deprecated `child-N` alias so that
|
|
8
|
+
* existing configs, custom prompts, or sessions that route via the old name
|
|
9
|
+
* keep working.
|
|
10
|
+
*/
|
|
11
|
+
export declare function createAgents(config?: PluginConfig, options?: {
|
|
12
|
+
projectDirectory?: string;
|
|
13
|
+
}): AgentDefinition[];
|
|
14
|
+
/**
|
|
15
|
+
* Get agent configurations formatted for the OpenCode SDK.
|
|
16
|
+
*/
|
|
17
|
+
export declare function getAgentConfigs(config?: PluginConfig, options?: {
|
|
18
|
+
projectDirectory?: string;
|
|
19
|
+
}): Record<string, SDKAgentConfig>;
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import type { MyrmidonConfig } from '../config';
|
|
2
|
+
import type { AgentDefinition } from './titan';
|
|
3
|
+
export declare function createMyrmidonAgent(index: number, config: MyrmidonConfig): AgentDefinition;
|
|
4
|
+
/**
|
|
5
|
+
* @deprecated Use `createMyrmidonAgent`. Retained as a backwards-compatible
|
|
6
|
+
* alias for the former "child agent" naming.
|
|
7
|
+
*/
|
|
8
|
+
export declare const createChildAgent: typeof createMyrmidonAgent;
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import type { AgentConfig } from '@opencode-ai/sdk/v2';
|
|
2
|
+
import type { MyrmidonConfig } from '../config';
|
|
3
|
+
export interface AgentDefinition {
|
|
4
|
+
name: string;
|
|
5
|
+
displayName?: string;
|
|
6
|
+
description?: string;
|
|
7
|
+
config: AgentConfig;
|
|
8
|
+
}
|
|
9
|
+
/**
|
|
10
|
+
* Resolve agent prompt from base/custom/append inputs.
|
|
11
|
+
*/
|
|
12
|
+
export declare function resolvePrompt(base: string, customPrompt?: string, customAppendPrompt?: string): string;
|
|
13
|
+
/**
|
|
14
|
+
* Build the Titan prompt with Myrmidon descriptions dynamically injected.
|
|
15
|
+
*/
|
|
16
|
+
export declare function buildTitanPrompt(myrmidons: MyrmidonConfig[]): string;
|
|
17
|
+
export declare function createTitanAgent(myrmidons: MyrmidonConfig[], model?: string, customPrompt?: string, customAppendPrompt?: string): AgentDefinition;
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
export declare const TITAN_AGENT_NAME: "titan";
|
|
2
|
+
export declare const ALL_AGENT_NAMES: readonly ["titan"];
|
|
3
|
+
export type AgentName = (typeof ALL_AGENT_NAMES)[number];
|
|
4
|
+
/** Agents that cannot be disabled. */
|
|
5
|
+
export declare const PROTECTED_AGENTS: Set<"titan">;
|
|
6
|
+
export declare const DELEGATION_REMINDER = "<internal_reminder>DELEGATE EVERYTHING POSSIBLE TO MYRMIDONS. You are the slowest agent by far - your only job is planning, routing, and synthesizing results. Never do work a Myrmidon can handle. Parallelize aggressively: tool calls made in the SAME response turn run concurrently \u2014 always batch all ready task() dispatches into ONE response, never one per turn. SAY WHAT YOU DO: if you announce launching N Myrmidons, emit exactly N task() calls in that same response \u2014 never announce multiple then dispatch only one. Before ending a dispatch turn, count your task() calls and confirm they match the number of Myrmidons you named. The task() tool takes only subagent_type, description, and prompt \u2014 never pass any other parameters. </internal_reminder>";
|
|
7
|
+
/**
|
|
8
|
+
* Sentinel substring used to detect whether {@link DELEGATION_REMINDER} has
|
|
9
|
+
* already been injected into a system prompt, avoiding double-injection.
|
|
10
|
+
*/
|
|
11
|
+
export declare const DELEGATION_REMINDER_SENTINEL = "DELEGATE EVERYTHING POSSIBLE TO MYRMIDONS";
|
|
12
|
+
/**
|
|
13
|
+
* Per-message reminder injected into EVERY user turn addressed to Titan.
|
|
14
|
+
*
|
|
15
|
+
* The static system prompt reliably drives delegation on the first request, but
|
|
16
|
+
* as a conversation shifts to iterating/tweaking the original task, Titan tends
|
|
17
|
+
* to drift toward doing the work itself. Re-asserting the delegation directive
|
|
18
|
+
* at the point of each new user message keeps that behavior consistent — it
|
|
19
|
+
* mimics the user manually prefixing "delegate this" onto every ask.
|
|
20
|
+
*/
|
|
21
|
+
export declare const PER_MESSAGE_DELEGATION_REMINDER = "<delegation_directive>\nBefore you act on the user's message above, STOP and route it through delegation first.\n\n1. Decompose the request (including any follow-up tweaks, fixes, or refinements to prior work) into concrete units of work.\n2. For every unit that would require even a SINGLE tool call \u2014 reading/searching/editing files, running commands, testing, validating, looking things up, gathering information, or any mechanical work \u2014 you MUST delegate it to Myrmidons via task(). This applies to small iterative changes on the existing task just as much as to brand-new work. Do NOT do it yourself because it \"seems quick.\"\n3. Dispatch all independent units in parallel: emit one task() call per unit in a SINGLE response, and make the number of task() calls match the number of Myrmidons you announce.\n4. The ONLY time you may answer directly without delegating is when the request is trivially simple, purely conversational, and requires zero tool calls (e.g., clarifying a question, restating a plan, a one-word answer). When in doubt, delegate.\n\nTreat this as if the user explicitly said: \"delegate this to your Myrmidons.\"\n</delegation_directive>";
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
export * from './constants';
|
|
2
|
+
export { deepMerge, loadAgentPrompt, loadPluginConfig, } from './loader';
|
|
3
|
+
export type { AgentLockInfo } from './providers';
|
|
4
|
+
export { buildAgentLockInfoMap, buildAgentProviderMap, resolveChildProvider, resolveMyrmidonProvider, } from './providers';
|
|
5
|
+
export * from './schema';
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import { type PluginConfig } from './schema';
|
|
2
|
+
export declare function findPluginConfigPaths(directory: string): {
|
|
3
|
+
userConfigPath: string | null;
|
|
4
|
+
projectConfigPath: string | null;
|
|
5
|
+
};
|
|
6
|
+
export declare function deepMerge<T extends Record<string, unknown>>(base?: T, override?: T): T | undefined;
|
|
7
|
+
export declare function mergePluginConfigs(base: PluginConfig, override: PluginConfig): PluginConfig;
|
|
8
|
+
/**
|
|
9
|
+
* Load plugin configuration from user and project config files.
|
|
10
|
+
*/
|
|
11
|
+
export declare function loadPluginConfig(directory: string): PluginConfig;
|
|
12
|
+
/**
|
|
13
|
+
* Load custom prompt for an agent from the prompts directory.
|
|
14
|
+
*/
|
|
15
|
+
export declare function loadAgentPrompt(agentName: string, options?: {
|
|
16
|
+
preset?: string;
|
|
17
|
+
projectDirectory?: string;
|
|
18
|
+
}): {
|
|
19
|
+
prompt?: string;
|
|
20
|
+
appendPrompt?: string;
|
|
21
|
+
};
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
import type { MyrmidonConfig } from './schema';
|
|
2
|
+
/**
|
|
3
|
+
* Resolve the logical provider for a Myrmidon.
|
|
4
|
+
*
|
|
5
|
+
* A "provider" here represents the physical backend (machine/host) that serves
|
|
6
|
+
* the model. Multiple Myrmidons may share a provider when they run on the same
|
|
7
|
+
* hardware — in which case only one of them can be active at a time (e.g.
|
|
8
|
+
* because only one model fits in that machine's VRAM at any moment).
|
|
9
|
+
*
|
|
10
|
+
* Falls back to the provider prefix of the `provider/model` string when no
|
|
11
|
+
* explicit `provider` is configured.
|
|
12
|
+
*/
|
|
13
|
+
export declare function resolveMyrmidonProvider(myrmidon: MyrmidonConfig): string;
|
|
14
|
+
/**
|
|
15
|
+
* @deprecated Use `resolveMyrmidonProvider`. Retained as a backwards-compatible
|
|
16
|
+
* alias for the former "child agent" naming.
|
|
17
|
+
*/
|
|
18
|
+
export declare const resolveChildProvider: typeof resolveMyrmidonProvider;
|
|
19
|
+
/**
|
|
20
|
+
* Build a map from Myrmidon agent name to its resolved provider. Each Myrmidon
|
|
21
|
+
* is registered under its canonical name (`myrmidon-0`, `myrmidon-1`, ...) and
|
|
22
|
+
* its deprecated alias (`child-0`, `child-1`, ...) so routing keeps working for
|
|
23
|
+
* either name. The index in the array determines the agent name, matching
|
|
24
|
+
* `createMyrmidonAgent`.
|
|
25
|
+
*/
|
|
26
|
+
export declare function buildAgentProviderMap(myrmidons: MyrmidonConfig[]): Map<string, string>;
|
|
27
|
+
/**
|
|
28
|
+
* Runtime lock metadata for a Myrmidon.
|
|
29
|
+
*
|
|
30
|
+
* `provider` is the physical backend; `model` identifies what is loaded into
|
|
31
|
+
* that backend's VRAM. Multiple instances of the *same* model may run
|
|
32
|
+
* concurrently on a provider (up to `maxInstances`), but different models on the
|
|
33
|
+
* same provider must be serialized.
|
|
34
|
+
*/
|
|
35
|
+
export interface AgentLockInfo {
|
|
36
|
+
provider: string;
|
|
37
|
+
model: string;
|
|
38
|
+
maxInstances: number;
|
|
39
|
+
}
|
|
40
|
+
/**
|
|
41
|
+
* Build a map from Myrmidon agent name to the lock metadata used to enforce the
|
|
42
|
+
* per-provider, per-model concurrency constraint at runtime. Both the canonical
|
|
43
|
+
* name (`myrmidon-N`) and the deprecated alias (`child-N`) are registered so
|
|
44
|
+
* the runtime lock applies regardless of which routing name is used.
|
|
45
|
+
*/
|
|
46
|
+
export declare function buildAgentLockInfoMap(myrmidons: MyrmidonConfig[]): Map<string, AgentLockInfo>;
|
|
@@ -0,0 +1,98 @@
|
|
|
1
|
+
import { z } from 'zod';
|
|
2
|
+
export declare const ProviderModelIdSchema: z.ZodString;
|
|
3
|
+
export declare const ModelTypeSchema: z.ZodEnum<{
|
|
4
|
+
dense: "dense";
|
|
5
|
+
sparse: "sparse";
|
|
6
|
+
}>;
|
|
7
|
+
export type ModelType = z.infer<typeof ModelTypeSchema>;
|
|
8
|
+
export declare const MyrmidonConfigSchema: z.ZodObject<{
|
|
9
|
+
model: z.ZodUnion<readonly [z.ZodString, z.ZodString]>;
|
|
10
|
+
speed: z.ZodNumber;
|
|
11
|
+
intelligence: z.ZodNumber;
|
|
12
|
+
modelType: z.ZodEnum<{
|
|
13
|
+
dense: "dense";
|
|
14
|
+
sparse: "sparse";
|
|
15
|
+
}>;
|
|
16
|
+
maxInstances: z.ZodOptional<z.ZodNumber>;
|
|
17
|
+
temperature: z.ZodOptional<z.ZodNumber>;
|
|
18
|
+
variant: z.ZodOptional<z.ZodString>;
|
|
19
|
+
displayName: z.ZodOptional<z.ZodString>;
|
|
20
|
+
provider: z.ZodOptional<z.ZodString>;
|
|
21
|
+
}, z.core.$strict>;
|
|
22
|
+
export type MyrmidonConfig = z.infer<typeof MyrmidonConfigSchema>;
|
|
23
|
+
/**
|
|
24
|
+
* @deprecated Use `MyrmidonConfigSchema`. Retained as a backwards-compatible
|
|
25
|
+
* alias for the former "child agent" naming.
|
|
26
|
+
*/
|
|
27
|
+
export declare const ChildAgentConfigSchema: z.ZodObject<{
|
|
28
|
+
model: z.ZodUnion<readonly [z.ZodString, z.ZodString]>;
|
|
29
|
+
speed: z.ZodNumber;
|
|
30
|
+
intelligence: z.ZodNumber;
|
|
31
|
+
modelType: z.ZodEnum<{
|
|
32
|
+
dense: "dense";
|
|
33
|
+
sparse: "sparse";
|
|
34
|
+
}>;
|
|
35
|
+
maxInstances: z.ZodOptional<z.ZodNumber>;
|
|
36
|
+
temperature: z.ZodOptional<z.ZodNumber>;
|
|
37
|
+
variant: z.ZodOptional<z.ZodString>;
|
|
38
|
+
displayName: z.ZodOptional<z.ZodString>;
|
|
39
|
+
provider: z.ZodOptional<z.ZodString>;
|
|
40
|
+
}, z.core.$strict>;
|
|
41
|
+
/**
|
|
42
|
+
* @deprecated Use `MyrmidonConfig`. Retained as a backwards-compatible alias
|
|
43
|
+
* for the former "child agent" naming.
|
|
44
|
+
*/
|
|
45
|
+
export type ChildAgentConfig = MyrmidonConfig;
|
|
46
|
+
export declare const TitanOverrideConfigSchema: z.ZodObject<{
|
|
47
|
+
model: z.ZodOptional<z.ZodUnion<readonly [z.ZodString, z.ZodString]>>;
|
|
48
|
+
temperature: z.ZodOptional<z.ZodNumber>;
|
|
49
|
+
variant: z.ZodOptional<z.ZodString>;
|
|
50
|
+
prompt: z.ZodOptional<z.ZodString>;
|
|
51
|
+
}, z.core.$strict>;
|
|
52
|
+
export type TitanOverrideConfig = z.infer<typeof TitanOverrideConfigSchema>;
|
|
53
|
+
export declare const PluginConfigSchema: z.ZodObject<{
|
|
54
|
+
titan: z.ZodOptional<z.ZodObject<{
|
|
55
|
+
model: z.ZodOptional<z.ZodUnion<readonly [z.ZodString, z.ZodString]>>;
|
|
56
|
+
temperature: z.ZodOptional<z.ZodNumber>;
|
|
57
|
+
variant: z.ZodOptional<z.ZodString>;
|
|
58
|
+
prompt: z.ZodOptional<z.ZodString>;
|
|
59
|
+
}, z.core.$strict>>;
|
|
60
|
+
myrmidons: z.ZodOptional<z.ZodArray<z.ZodObject<{
|
|
61
|
+
model: z.ZodUnion<readonly [z.ZodString, z.ZodString]>;
|
|
62
|
+
speed: z.ZodNumber;
|
|
63
|
+
intelligence: z.ZodNumber;
|
|
64
|
+
modelType: z.ZodEnum<{
|
|
65
|
+
dense: "dense";
|
|
66
|
+
sparse: "sparse";
|
|
67
|
+
}>;
|
|
68
|
+
maxInstances: z.ZodOptional<z.ZodNumber>;
|
|
69
|
+
temperature: z.ZodOptional<z.ZodNumber>;
|
|
70
|
+
variant: z.ZodOptional<z.ZodString>;
|
|
71
|
+
displayName: z.ZodOptional<z.ZodString>;
|
|
72
|
+
provider: z.ZodOptional<z.ZodString>;
|
|
73
|
+
}, z.core.$strict>>>;
|
|
74
|
+
children: z.ZodOptional<z.ZodArray<z.ZodObject<{
|
|
75
|
+
model: z.ZodUnion<readonly [z.ZodString, z.ZodString]>;
|
|
76
|
+
speed: z.ZodNumber;
|
|
77
|
+
intelligence: z.ZodNumber;
|
|
78
|
+
modelType: z.ZodEnum<{
|
|
79
|
+
dense: "dense";
|
|
80
|
+
sparse: "sparse";
|
|
81
|
+
}>;
|
|
82
|
+
maxInstances: z.ZodOptional<z.ZodNumber>;
|
|
83
|
+
temperature: z.ZodOptional<z.ZodNumber>;
|
|
84
|
+
variant: z.ZodOptional<z.ZodString>;
|
|
85
|
+
displayName: z.ZodOptional<z.ZodString>;
|
|
86
|
+
provider: z.ZodOptional<z.ZodString>;
|
|
87
|
+
}, z.core.$strict>>>;
|
|
88
|
+
disabled_tools: z.ZodOptional<z.ZodArray<z.ZodString>>;
|
|
89
|
+
backgroundJobs: z.ZodOptional<z.ZodObject<{
|
|
90
|
+
maxSessionsPerAgent: z.ZodDefault<z.ZodNumber>;
|
|
91
|
+
}, z.core.$strip>>;
|
|
92
|
+
}, z.core.$strip>;
|
|
93
|
+
export type PluginConfig = z.infer<typeof PluginConfigSchema>;
|
|
94
|
+
/**
|
|
95
|
+
* Resolve the configured Myrmidon fleet, honoring the deprecated `children`
|
|
96
|
+
* key. `myrmidons` takes precedence when both are provided.
|
|
97
|
+
*/
|
|
98
|
+
export declare function getMyrmidonConfigs(config?: PluginConfig): MyrmidonConfig[];
|
package/dist/index.d.ts
ADDED