opencode-titan 0.1.0 → 0.1.1
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 +31 -3
- package/dist/agents/myrmidon.d.ts +2 -2
- package/dist/agents/titan.d.ts +2 -2
- package/dist/config/constants.d.ts +5 -0
- package/dist/config/schema.d.ts +1 -0
- package/dist/index.js +19 -9
- package/opencode-titan.schema.json +6 -0
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -1,6 +1,9 @@
|
|
|
1
1
|
<div align="center">
|
|
2
2
|
<h3>⚡ opencode-titan ⚡</h3>
|
|
3
3
|
|
|
4
|
+
<img src="assets/titan-demo.gif" alt="opencode-titan demo" width="100%">
|
|
5
|
+
|
|
6
|
+
|
|
4
7
|
<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
8
|
|
|
6
9
|
<p><b>OpenCode Orchestration Plugin</b> · Mix any models · Delegate everything · Run in parallel</p>
|
|
@@ -32,8 +35,30 @@ The plugin builds a two-tier hierarchy of agents:
|
|
|
32
35
|
|
|
33
36
|
## Installation
|
|
34
37
|
|
|
35
|
-
|
|
36
|
-
|
|
38
|
+
Add the [`opencode-titan`](https://www.npmjs.com/package/opencode-titan) package to the `plugin` array in your OpenCode config (`opencode.json`). OpenCode installs it automatically from npm on startup:
|
|
39
|
+
|
|
40
|
+
```json
|
|
41
|
+
{
|
|
42
|
+
"$schema": "https://opencode.ai/config.json",
|
|
43
|
+
"plugin": ["opencode-titan"]
|
|
44
|
+
}
|
|
45
|
+
```
|
|
46
|
+
|
|
47
|
+
To pin a specific version, append it with `@`:
|
|
48
|
+
|
|
49
|
+
```json
|
|
50
|
+
{
|
|
51
|
+
"$schema": "https://opencode.ai/config.json",
|
|
52
|
+
"plugin": ["opencode-titan@0.1.0"]
|
|
53
|
+
}
|
|
54
|
+
```
|
|
55
|
+
|
|
56
|
+
Restart OpenCode and Titan becomes your default agent.
|
|
57
|
+
|
|
58
|
+
<details>
|
|
59
|
+
<summary><b>Alternative: install from source</b></summary>
|
|
60
|
+
|
|
61
|
+
Use this if you want to hack on the plugin or run an unreleased version.
|
|
37
62
|
|
|
38
63
|
**1. Clone and build the plugin:**
|
|
39
64
|
|
|
@@ -59,6 +84,8 @@ OpenCode treats any plugin entry starting with `.`, `file://`, or an absolute pa
|
|
|
59
84
|
|
|
60
85
|
Restart OpenCode and Titan becomes your default agent.
|
|
61
86
|
|
|
87
|
+
</details>
|
|
88
|
+
|
|
62
89
|
## Getting Started
|
|
63
90
|
|
|
64
91
|
1. **Create your plugin config** at `~/.config/opencode/opencode-titan.jsonc`
|
|
@@ -120,7 +147,7 @@ Titan is the most intelligent agent in the fleet, and by far the slowest and mos
|
|
|
120
147
|
|
|
121
148
|
### ⚙️ Myrmidons — The Fleet
|
|
122
149
|
|
|
123
|
-
Myrmidons are the hands. Each executes a delegated task and reports back concisely — responses to Titan are enforced to a single paragraph,
|
|
150
|
+
Myrmidons are the hands. Each executes a delegated task and reports back concisely — responses to Titan are enforced to a single paragraph, 1000 words max by default (configurable via `maxResponseWords`), keeping Titan's context lean. Every Myrmidon declares a `modelType` that shapes how Titan routes work to it:
|
|
124
151
|
|
|
125
152
|
<table>
|
|
126
153
|
<tr>
|
|
@@ -172,6 +199,7 @@ Myrmidons are the hands. Each executes a delegated task and reports back concise
|
|
|
172
199
|
| `myrmidons` | `array` | The Myrmidon fleet (see above) |
|
|
173
200
|
| `children` | `array` | **Deprecated** alias for `myrmidons`, kept for backwards compatibility. Prefer `myrmidons`; if both are set, `myrmidons` wins |
|
|
174
201
|
| `disabled_tools` | `string[]` | Tool names to disable for the plugin's agents |
|
|
202
|
+
| `maxResponseWords` | `number` (≥1) | Max word count enforced on each Myrmidon's one-paragraph response to Titan (default: `1000`) |
|
|
175
203
|
| `backgroundJobs.maxSessionsPerAgent` | `number` (1–10) | Max concurrent sessions per agent (default: `10`) |
|
|
176
204
|
|
|
177
205
|
### Config Locations
|
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
import type
|
|
1
|
+
import { type MyrmidonConfig } from '../config';
|
|
2
2
|
import type { AgentDefinition } from './titan';
|
|
3
|
-
export declare function createMyrmidonAgent(index: number, config: MyrmidonConfig): AgentDefinition;
|
|
3
|
+
export declare function createMyrmidonAgent(index: number, config: MyrmidonConfig, maxResponseWords?: number): AgentDefinition;
|
|
4
4
|
/**
|
|
5
5
|
* @deprecated Use `createMyrmidonAgent`. Retained as a backwards-compatible
|
|
6
6
|
* alias for the former "child agent" naming.
|
package/dist/agents/titan.d.ts
CHANGED
|
@@ -13,5 +13,5 @@ export declare function resolvePrompt(base: string, customPrompt?: string, custo
|
|
|
13
13
|
/**
|
|
14
14
|
* Build the Titan prompt with Myrmidon descriptions dynamically injected.
|
|
15
15
|
*/
|
|
16
|
-
export declare function buildTitanPrompt(myrmidons: MyrmidonConfig[]): string;
|
|
17
|
-
export declare function createTitanAgent(myrmidons: MyrmidonConfig[], model?: string, customPrompt?: string, customAppendPrompt?: string): AgentDefinition;
|
|
16
|
+
export declare function buildTitanPrompt(myrmidons: MyrmidonConfig[], maxResponseWords?: number): string;
|
|
17
|
+
export declare function createTitanAgent(myrmidons: MyrmidonConfig[], model?: string, customPrompt?: string, customAppendPrompt?: string, maxResponseWords?: number): AgentDefinition;
|
|
@@ -1,4 +1,9 @@
|
|
|
1
1
|
export declare const TITAN_AGENT_NAME: "titan";
|
|
2
|
+
/**
|
|
3
|
+
* Default maximum word count enforced on a Myrmidon's final response to Titan.
|
|
4
|
+
* Overridable via the `maxResponseWords` plugin config key.
|
|
5
|
+
*/
|
|
6
|
+
export declare const DEFAULT_MAX_RESPONSE_WORDS: 1000;
|
|
2
7
|
export declare const ALL_AGENT_NAMES: readonly ["titan"];
|
|
3
8
|
export type AgentName = (typeof ALL_AGENT_NAMES)[number];
|
|
4
9
|
/** Agents that cannot be disabled. */
|
package/dist/config/schema.d.ts
CHANGED
|
@@ -85,6 +85,7 @@ export declare const PluginConfigSchema: z.ZodObject<{
|
|
|
85
85
|
displayName: z.ZodOptional<z.ZodString>;
|
|
86
86
|
provider: z.ZodOptional<z.ZodString>;
|
|
87
87
|
}, z.core.$strict>>>;
|
|
88
|
+
maxResponseWords: z.ZodOptional<z.ZodNumber>;
|
|
88
89
|
disabled_tools: z.ZodOptional<z.ZodArray<z.ZodString>>;
|
|
89
90
|
backgroundJobs: z.ZodOptional<z.ZodObject<{
|
|
90
91
|
maxSessionsPerAgent: z.ZodDefault<z.ZodNumber>;
|
package/dist/index.js
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
// src/config/constants.ts
|
|
2
2
|
var TITAN_AGENT_NAME = "titan";
|
|
3
|
+
var DEFAULT_MAX_RESPONSE_WORDS = 1e3;
|
|
3
4
|
var 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>`;
|
|
4
5
|
var DELEGATION_REMINDER_SENTINEL = "DELEGATE EVERYTHING POSSIBLE TO MYRMIDONS";
|
|
5
6
|
var PER_MESSAGE_DELEGATION_REMINDER = `<delegation_directive>
|
|
@@ -51,6 +52,9 @@ var PluginConfigSchema = z.object({
|
|
|
51
52
|
// Deprecated alias for `myrmidons`, retained for backwards compatibility.
|
|
52
53
|
// If both are present, `myrmidons` takes precedence.
|
|
53
54
|
children: z.array(MyrmidonConfigSchema).optional(),
|
|
55
|
+
// Maximum word count enforced on each Myrmidon's final response to Titan.
|
|
56
|
+
// Keeps Titan's context lean. Defaults to DEFAULT_MAX_RESPONSE_WORDS (1000).
|
|
57
|
+
maxResponseWords: z.number().int().min(1).optional(),
|
|
54
58
|
disabled_tools: z.array(z.string()).optional(),
|
|
55
59
|
backgroundJobs: z.object({
|
|
56
60
|
maxSessionsPerAgent: z.number().int().min(1).max(10).default(10)
|
|
@@ -300,7 +304,7 @@ You are operating with a hard context budget. Exceeding it causes failure. Follo
|
|
|
300
304
|
</ContextBudget>
|
|
301
305
|
|
|
302
306
|
<OutputConstraints>
|
|
303
|
-
- **CRITICAL: Your final response to Titan MUST be ONE PARAGRAPH, no more than
|
|
307
|
+
- **CRITICAL: Your final response to Titan MUST be ONE PARAGRAPH, no more than {{MAX_WORDS}} words.**
|
|
304
308
|
- No preamble, no summary of what you did \u2014 just the results.
|
|
305
309
|
- Report success/failure clearly in your first sentence.
|
|
306
310
|
- Include only actionable details: file paths, line numbers, errors, generated code snippets.
|
|
@@ -317,10 +321,14 @@ You are operating with a hard context budget. Exceeding it causes failure. Follo
|
|
|
317
321
|
{{TASK_PROMPT}}
|
|
318
322
|
</Task>
|
|
319
323
|
`;
|
|
320
|
-
function createMyrmidonAgent(index, config) {
|
|
324
|
+
function createMyrmidonAgent(index, config, maxResponseWords = DEFAULT_MAX_RESPONSE_WORDS) {
|
|
321
325
|
const name = `myrmidon-${index}`;
|
|
322
326
|
const modelTypeHint = config.modelType === "dense" ? "You are running a dense model \u2014 you excel at logic, reasoning, and complex problem-solving. Use this strength for tasks requiring careful analysis." : "You are running a sparse model \u2014 you excel at fast information gathering, broad search, and rapid lookups. Use this strength for research and exploration tasks.";
|
|
323
|
-
const
|
|
327
|
+
const template = MYRMIDON_PROMPT_TEMPLATE.replace(
|
|
328
|
+
"{{MAX_WORDS}}",
|
|
329
|
+
String(maxResponseWords)
|
|
330
|
+
);
|
|
331
|
+
const prompt = `${template.replace("{{TASK_PROMPT}}", "")}
|
|
324
332
|
|
|
325
333
|
${modelTypeHint}`;
|
|
326
334
|
return {
|
|
@@ -348,7 +356,7 @@ function resolvePrompt(base, customPrompt, customAppendPrompt) {
|
|
|
348
356
|
|
|
349
357
|
${customAppendPrompt}` : effectiveBase;
|
|
350
358
|
}
|
|
351
|
-
function buildTitanPrompt(myrmidons) {
|
|
359
|
+
function buildTitanPrompt(myrmidons, maxResponseWords = DEFAULT_MAX_RESPONSE_WORDS) {
|
|
352
360
|
const resolveProvider = resolveMyrmidonProvider;
|
|
353
361
|
const myrmidonDescriptions = myrmidons.map((myrmidon, idx) => {
|
|
354
362
|
const name = `myrmidon-${idx}`;
|
|
@@ -539,14 +547,14 @@ When delegating to a Myrmidon:
|
|
|
539
547
|
- Be specific about the task and expected output format
|
|
540
548
|
- Reference file paths/lines, don't paste full contents
|
|
541
549
|
- Set clear boundaries: what to do and what not to do
|
|
542
|
-
- Tell the Myrmidon to report back concisely (one paragraph, under
|
|
550
|
+
- Tell the Myrmidon to report back concisely (one paragraph, under ${maxResponseWords} words max)
|
|
543
551
|
</CommunicationWithMyrmidons>
|
|
544
552
|
|
|
545
553
|
${DELEGATION_REMINDER}
|
|
546
554
|
`;
|
|
547
555
|
}
|
|
548
|
-
function createTitanAgent(myrmidons, model, customPrompt, customAppendPrompt) {
|
|
549
|
-
const basePrompt = buildTitanPrompt(myrmidons);
|
|
556
|
+
function createTitanAgent(myrmidons, model, customPrompt, customAppendPrompt, maxResponseWords = DEFAULT_MAX_RESPONSE_WORDS) {
|
|
557
|
+
const basePrompt = buildTitanPrompt(myrmidons, maxResponseWords);
|
|
550
558
|
const prompt = resolvePrompt(basePrompt, customPrompt, customAppendPrompt);
|
|
551
559
|
const definition = {
|
|
552
560
|
name: "titan",
|
|
@@ -565,6 +573,7 @@ function createTitanAgent(myrmidons, model, customPrompt, customAppendPrompt) {
|
|
|
565
573
|
// src/agents/index.ts
|
|
566
574
|
function createAgents(config, options) {
|
|
567
575
|
const myrmidons = getMyrmidonConfigs(config);
|
|
576
|
+
const maxResponseWords = config?.maxResponseWords ?? DEFAULT_MAX_RESPONSE_WORDS;
|
|
568
577
|
const titanModel = config?.titan?.model;
|
|
569
578
|
const titanPrompts = loadAgentPrompt("titan", {
|
|
570
579
|
projectDirectory: options?.projectDirectory
|
|
@@ -573,7 +582,8 @@ function createAgents(config, options) {
|
|
|
573
582
|
myrmidons,
|
|
574
583
|
typeof titanModel === "string" ? titanModel : void 0,
|
|
575
584
|
config?.titan?.prompt,
|
|
576
|
-
void 0
|
|
585
|
+
void 0,
|
|
586
|
+
maxResponseWords
|
|
577
587
|
);
|
|
578
588
|
titan.config.prompt = resolvePrompt(
|
|
579
589
|
titan.config.prompt ?? "",
|
|
@@ -589,7 +599,7 @@ function createAgents(config, options) {
|
|
|
589
599
|
}
|
|
590
600
|
}
|
|
591
601
|
const myrmidonAgents = myrmidons.map(
|
|
592
|
-
(myrmidonConfig, idx) => createMyrmidonAgent(idx, myrmidonConfig)
|
|
602
|
+
(myrmidonConfig, idx) => createMyrmidonAgent(idx, myrmidonConfig, maxResponseWords)
|
|
593
603
|
);
|
|
594
604
|
const aliasAgents = myrmidonAgents.map((agent, idx) => ({
|
|
595
605
|
...agent,
|
|
@@ -41,6 +41,12 @@
|
|
|
41
41
|
"$ref": "#/$defs/myrmidon"
|
|
42
42
|
}
|
|
43
43
|
},
|
|
44
|
+
"maxResponseWords": {
|
|
45
|
+
"type": "integer",
|
|
46
|
+
"minimum": 1,
|
|
47
|
+
"default": 1000,
|
|
48
|
+
"description": "Maximum word count enforced on each Myrmidon's final (one-paragraph) response to Titan. Keeps Titan's context lean. Defaults to 1000."
|
|
49
|
+
},
|
|
44
50
|
"disabled_tools": {
|
|
45
51
|
"type": "array",
|
|
46
52
|
"description": "Tool names to disable completely. Disabled tools are not registered with OpenCode.",
|