@rrr2010/opencode-roundtable 0.3.0 → 0.3.2
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 +244 -203
- package/dist/index.js +72 -15
- package/dist/index.js.map +8 -8
- package/docs/SPEC.md +974 -979
- package/package.json +60 -61
- package/src/tui/tui.tsx +89 -99
package/README.md
CHANGED
|
@@ -1,203 +1,244 @@
|
|
|
1
|
-
# opencode-roundtable
|
|
2
|
-
|
|
3
|
-
OpenCode plugin that orchestrates **multi-agent round-robin debates**.
|
|
4
|
-
Agents with different personalities debate a topic turn by turn, sharing
|
|
5
|
-
context while keeping their own system prompts and tools.
|
|
6
|
-
|
|
7
|
-
A built-in observer automatically consolidates every debate into an
|
|
8
|
-
executive summary.
|
|
9
|
-
|
|
10
|
-
## Installation
|
|
11
|
-
|
|
12
|
-
### npm (recommended)
|
|
13
|
-
|
|
14
|
-
```json
|
|
15
|
-
{
|
|
16
|
-
"plugin": ["@rrr2010/opencode-roundtable@latest"]
|
|
17
|
-
}
|
|
18
|
-
```
|
|
19
|
-
|
|
20
|
-
OpenCode auto-installs npm plugins on startup. No manual copy needed.
|
|
21
|
-
|
|
22
|
-
### Local (dev)
|
|
23
|
-
|
|
24
|
-
```bash
|
|
25
|
-
git clone https://github.com/opencode-ai/roundtable
|
|
26
|
-
cd roundtable
|
|
27
|
-
bun run build
|
|
28
|
-
npm link
|
|
29
|
-
```
|
|
30
|
-
|
|
31
|
-
Then add `"@rrr2010/opencode-roundtable"` to your opencode.json `plugin` array.
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
- **
|
|
39
|
-
- **
|
|
40
|
-
- **
|
|
41
|
-
- **
|
|
42
|
-
- **
|
|
43
|
-
- **
|
|
44
|
-
- **
|
|
45
|
-
- **
|
|
46
|
-
- **
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
**
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
available_agents()
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
```
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
1
|
+
# opencode-roundtable
|
|
2
|
+
|
|
3
|
+
OpenCode plugin that orchestrates **multi-agent round-robin debates**.
|
|
4
|
+
Agents with different personalities debate a topic turn by turn, sharing
|
|
5
|
+
context while keeping their own system prompts and tools.
|
|
6
|
+
|
|
7
|
+
A built-in observer automatically consolidates every debate into an
|
|
8
|
+
executive summary.
|
|
9
|
+
|
|
10
|
+
## Installation
|
|
11
|
+
|
|
12
|
+
### npm (recommended)
|
|
13
|
+
|
|
14
|
+
```json
|
|
15
|
+
{
|
|
16
|
+
"plugin": ["@rrr2010/opencode-roundtable@latest"]
|
|
17
|
+
}
|
|
18
|
+
```
|
|
19
|
+
|
|
20
|
+
OpenCode auto-installs npm plugins on startup. No manual copy needed.
|
|
21
|
+
|
|
22
|
+
### Local (dev)
|
|
23
|
+
|
|
24
|
+
```bash
|
|
25
|
+
git clone https://github.com/opencode-ai/roundtable
|
|
26
|
+
cd roundtable
|
|
27
|
+
bun run build
|
|
28
|
+
npm link
|
|
29
|
+
```
|
|
30
|
+
|
|
31
|
+
Then add `"@rrr2010/opencode-roundtable"` to your opencode.json `plugin` array.
|
|
32
|
+
|
|
33
|
+
## Features
|
|
34
|
+
|
|
35
|
+
- **Round-robin debate** — agents speak in sequence, each seeing the full discussion history
|
|
36
|
+
- **Shared context** — tool outputs and discoveries are visible to all participants
|
|
37
|
+
- **Built-in observer** — automatically consolidates the debate into an executive summary (overridable with a specific agent)
|
|
38
|
+
- **Isolated session** — the debate runs in a child session, keeping the main session clean
|
|
39
|
+
- **File persistence** — state stored on disk, survives restarts
|
|
40
|
+
- **Extend mode** — continue a concluded roundtable with more rounds or a new topic
|
|
41
|
+
- **Agent discovery** — `available_agents` tool helps the orchestrator know which agents exist
|
|
42
|
+
- **Active roundtables** — `active_roundtables` tool lists current debates with status
|
|
43
|
+
- **TUI plugin** — badge `[RT]`, `← Back` link, `/roundtables` command
|
|
44
|
+
- **Auto-navigate** — optional auto-navigation between sessions on create/conclude
|
|
45
|
+
- **Parallel roundtables** — multiple independent debates can run simultaneously
|
|
46
|
+
- **User intervention** — the human can jump into the debate at any time
|
|
47
|
+
- **Loop detection** — Jaccard bigram similarity detects agent impasses early
|
|
48
|
+
|
|
49
|
+
## Tool API
|
|
50
|
+
|
|
51
|
+
### `roundtable()`
|
|
52
|
+
|
|
53
|
+
```typescript
|
|
54
|
+
roundtable({
|
|
55
|
+
agents?: string[], // Names in speaking order (min 2). Required for new debates.
|
|
56
|
+
prompt: string, // Topic or challenge. For multi-round, include per-round instructions.
|
|
57
|
+
rounds?: number, // Complete rounds (default: 1, max: 50)
|
|
58
|
+
observer?: string, // Agent for final consolidation (default: built-in)
|
|
59
|
+
sessionID?: string, // ses_xxxx — pass to extend a concluded debate
|
|
60
|
+
title?: string, // Custom title (default: auto-generated from prompt)
|
|
61
|
+
observerPrompt?: string, // Override the observer consolidation prompt (e.g., "Save a detailed report to report.md")
|
|
62
|
+
})
|
|
63
|
+
```
|
|
64
|
+
|
|
65
|
+
**Returns:** `{ sessionID: string, summary: string }` after the debate concludes.
|
|
66
|
+
|
|
67
|
+
**Side effect:** injects system-level prompts into each agent's context during
|
|
68
|
+
the debate (role-setting, topic, turn routing, and lifecycle signals).
|
|
69
|
+
|
|
70
|
+
### `available_agents()`
|
|
71
|
+
|
|
72
|
+
```typescript
|
|
73
|
+
available_agents()
|
|
74
|
+
```
|
|
75
|
+
|
|
76
|
+
**Returns:** `"Available agents: pm, dev, rv, ..."` — a formatted string of agent names.
|
|
77
|
+
|
|
78
|
+
### `active_roundtables()`
|
|
79
|
+
|
|
80
|
+
```typescript
|
|
81
|
+
active_roundtables()
|
|
82
|
+
```
|
|
83
|
+
|
|
84
|
+
**Returns:** clickable session listings with status, e.g.:
|
|
85
|
+
```
|
|
86
|
+
Active roundtables:
|
|
87
|
+
- #ses_xxx · pm→dev→rv (R1/2) · debating
|
|
88
|
+
- #ses_yyy · pm→dev (R2/2) · consolidating
|
|
89
|
+
```
|
|
90
|
+
|
|
91
|
+
## Usage Examples
|
|
92
|
+
|
|
93
|
+
### Basic — one round, built-in observer
|
|
94
|
+
|
|
95
|
+
```typescript
|
|
96
|
+
roundtable({
|
|
97
|
+
agents: ["pm", "dev"],
|
|
98
|
+
prompt: "What architecture should we use?",
|
|
99
|
+
})
|
|
100
|
+
```
|
|
101
|
+
|
|
102
|
+
### Multi-round with per-round instructions
|
|
103
|
+
|
|
104
|
+
```typescript
|
|
105
|
+
roundtable({
|
|
106
|
+
agents: ["pm", "dev"],
|
|
107
|
+
prompt: "Round 1: list pros. Round 2: list cons. Round 3: propose an implementation plan.",
|
|
108
|
+
rounds: 3,
|
|
109
|
+
})
|
|
110
|
+
```
|
|
111
|
+
|
|
112
|
+
### Explicit observer
|
|
113
|
+
|
|
114
|
+
```typescript
|
|
115
|
+
roundtable({
|
|
116
|
+
agents: ["pm", "dev"],
|
|
117
|
+
prompt: "Should we migrate to microservices?",
|
|
118
|
+
rounds: 2,
|
|
119
|
+
observer: "rv",
|
|
120
|
+
})
|
|
121
|
+
```
|
|
122
|
+
|
|
123
|
+
### Extend a concluded debate
|
|
124
|
+
|
|
125
|
+
```typescript
|
|
126
|
+
roundtable({
|
|
127
|
+
sessionID: "ses_abc123",
|
|
128
|
+
rounds: 2,
|
|
129
|
+
prompt: "Dive deeper into operational costs",
|
|
130
|
+
})
|
|
131
|
+
```
|
|
132
|
+
|
|
133
|
+
The session ID is shown in the S1 noReply message when the roundtable
|
|
134
|
+
starts — check S1 context to find it.
|
|
135
|
+
|
|
136
|
+
### Discover agents first
|
|
137
|
+
|
|
138
|
+
```typescript
|
|
139
|
+
const agents = available_agents()
|
|
140
|
+
// agents => "Available agents: pm, dev, rv, build, plan"
|
|
141
|
+
roundtable({
|
|
142
|
+
agents: ["pm", "dev"],
|
|
143
|
+
prompt: "...",
|
|
144
|
+
})
|
|
145
|
+
```
|
|
146
|
+
|
|
147
|
+
### List active roundtables
|
|
148
|
+
|
|
149
|
+
```typescript
|
|
150
|
+
const active = active_roundtables()
|
|
151
|
+
// active => "Active roundtables:\n- #ses_xxx · pm→dev (R1/2) · debating"
|
|
152
|
+
```
|
|
153
|
+
|
|
154
|
+
## Configuration
|
|
155
|
+
|
|
156
|
+
Place `~/.config/opencode/roundtable.json` to override defaults:
|
|
157
|
+
|
|
158
|
+
```json
|
|
159
|
+
{
|
|
160
|
+
"$schema": "https://raw.githubusercontent.com/opencode-ai/roundtable/main/docs/roundtable.schema.json",
|
|
161
|
+
"defaultTimeoutMs": 300000,
|
|
162
|
+
"loopSimilarityThreshold": 0.85,
|
|
163
|
+
"toolOutputPreviewMax": 500,
|
|
164
|
+
"maxRounds": 10,
|
|
165
|
+
"defaultObserverPrompt": "You are an impartial roundtable observer...",
|
|
166
|
+
"navigation": "link"
|
|
167
|
+
}
|
|
168
|
+
```
|
|
169
|
+
|
|
170
|
+
If the file doesn't exist, it's created automatically with defaults.
|
|
171
|
+
|
|
172
|
+
### Navigation modes
|
|
173
|
+
|
|
174
|
+
| Value | Behavior |
|
|
175
|
+
|-------|----------|
|
|
176
|
+
| `"link"` (default) | No auto-navigation. Relies on native `#ses_xxx` link rendering |
|
|
177
|
+
| `"auto"` | Auto-navigates S1→S2 on create, S2→S1 on conclude |
|
|
178
|
+
| `"none"` | No automatic navigation |
|
|
179
|
+
|
|
180
|
+
### TUI Features
|
|
181
|
+
|
|
182
|
+
The plugin registers a TUI component that provides:
|
|
183
|
+
|
|
184
|
+
- **`[RT]` badge** — shown in the sidebar for roundtable sessions
|
|
185
|
+
- **`← Back` link** — clickable link on child sessions, navigates to parent
|
|
186
|
+
- **`/roundtables` command** — slash command opens a dialog with clickable session list
|
|
187
|
+
|
|
188
|
+
## Tips
|
|
189
|
+
|
|
190
|
+
### Agent selection
|
|
191
|
+
|
|
192
|
+
Choose agents whose expertise matches the topic:
|
|
193
|
+
|
|
194
|
+
| Agent | Best for |
|
|
195
|
+
|-------|----------|
|
|
196
|
+
| `pm` | Product decisions, strategy, trade-offs |
|
|
197
|
+
| `dev` | Technical complexity, implementation effort |
|
|
198
|
+
| `rv` | Code review, docs quality, inconsistency detection |
|
|
199
|
+
| `plan` | Architecture planning, scope definition |
|
|
200
|
+
| `build` | Implementation details, execution |
|
|
201
|
+
|
|
202
|
+
### Multi-round strategy
|
|
203
|
+
|
|
204
|
+
For complex topics, structure rounds progressively:
|
|
205
|
+
|
|
206
|
+
1. **Round 1:** Explore — each agent lists their perspective
|
|
207
|
+
2. **Round 2:** Challenge — agents critique each other's positions
|
|
208
|
+
3. **Round 3+:** Converge — propose concrete solutions
|
|
209
|
+
|
|
210
|
+
Include all round instructions in the `prompt` parameter — all agents see the full agenda.
|
|
211
|
+
|
|
212
|
+
### Extend mode
|
|
213
|
+
|
|
214
|
+
- Use the session ID from the S1 noReply message when the roundtable starts
|
|
215
|
+
- Original topic is preserved; new prompt becomes the continuation
|
|
216
|
+
- Agents must be the same as the original debate (validated)
|
|
217
|
+
- Continue an extend for iterative refinement
|
|
218
|
+
|
|
219
|
+
## Agent colors (recommended)
|
|
220
|
+
|
|
221
|
+
```json
|
|
222
|
+
{
|
|
223
|
+
"agent": {
|
|
224
|
+
"pm": { "color": "#3498db" },
|
|
225
|
+
"dev": { "color": "#2ecc71" },
|
|
226
|
+
"rv": { "color": "#e74c3c" },
|
|
227
|
+
"plan": { "color": "#f39c12" },
|
|
228
|
+
"build": { "color": "#9b59b6" }
|
|
229
|
+
}
|
|
230
|
+
}
|
|
231
|
+
```
|
|
232
|
+
|
|
233
|
+
## Documentation
|
|
234
|
+
|
|
235
|
+
- [docs/SPEC.md](./docs/SPEC.md) — Full technical specification
|
|
236
|
+
|
|
237
|
+
## Requirements
|
|
238
|
+
|
|
239
|
+
- OpenCode (latest version)
|
|
240
|
+
- No external dependencies
|
|
241
|
+
|
|
242
|
+
## License
|
|
243
|
+
|
|
244
|
+
MIT
|
package/dist/index.js
CHANGED
|
@@ -28,7 +28,8 @@ var DEFAULT_CONFIG = {
|
|
|
28
28
|
"5. **Suggested next steps**"
|
|
29
29
|
].join(`
|
|
30
30
|
`),
|
|
31
|
-
maxRounds: 10
|
|
31
|
+
maxRounds: 10,
|
|
32
|
+
navigation: "link"
|
|
32
33
|
};
|
|
33
34
|
var config = { ...DEFAULT_CONFIG };
|
|
34
35
|
function getConfig() {
|
|
@@ -40,7 +41,8 @@ function validateConfig(raw) {
|
|
|
40
41
|
loopSimilarityThreshold: typeof raw.loopSimilarityThreshold === "number" && raw.loopSimilarityThreshold >= 0 && raw.loopSimilarityThreshold <= 1 ? raw.loopSimilarityThreshold : DEFAULT_CONFIG.loopSimilarityThreshold,
|
|
41
42
|
toolOutputPreviewMax: typeof raw.toolOutputPreviewMax === "number" && raw.toolOutputPreviewMax >= 100 ? raw.toolOutputPreviewMax : DEFAULT_CONFIG.toolOutputPreviewMax,
|
|
42
43
|
defaultObserverPrompt: typeof raw.defaultObserverPrompt === "string" && raw.defaultObserverPrompt.length > 0 ? raw.defaultObserverPrompt : DEFAULT_CONFIG.defaultObserverPrompt,
|
|
43
|
-
maxRounds: typeof raw.maxRounds === "number" && raw.maxRounds >= 1 ? raw.maxRounds : DEFAULT_CONFIG.maxRounds
|
|
44
|
+
maxRounds: typeof raw.maxRounds === "number" && raw.maxRounds >= 1 ? raw.maxRounds : DEFAULT_CONFIG.maxRounds,
|
|
45
|
+
navigation: raw.navigation === "selectSession" || raw.navigation === "none" || raw.navigation === "auto" ? raw.navigation : DEFAULT_CONFIG.navigation
|
|
44
46
|
};
|
|
45
47
|
}
|
|
46
48
|
async function loadConfig(ctx) {
|
|
@@ -335,6 +337,23 @@ Continuation: ${extendPrompt}`;
|
|
|
335
337
|
].join(`
|
|
336
338
|
`);
|
|
337
339
|
}
|
|
340
|
+
async function navigateToSession(ctx, targetID, _parentID) {
|
|
341
|
+
try {
|
|
342
|
+
if (typeof ctx.client.tui.selectSession === "function") {
|
|
343
|
+
await ctx.client.tui.selectSession({ sessionID: targetID });
|
|
344
|
+
return true;
|
|
345
|
+
}
|
|
346
|
+
await ctx.client.tui.publish({
|
|
347
|
+
body: {
|
|
348
|
+
type: "tui.session.select",
|
|
349
|
+
properties: { sessionID: targetID }
|
|
350
|
+
}
|
|
351
|
+
});
|
|
352
|
+
return true;
|
|
353
|
+
} catch {
|
|
354
|
+
return false;
|
|
355
|
+
}
|
|
356
|
+
}
|
|
338
357
|
async function scanOrphanRoundtables(ctx) {
|
|
339
358
|
const sessionIDs = await listStateFiles();
|
|
340
359
|
let loaded = 0;
|
|
@@ -380,11 +399,11 @@ function buildAgentPrompt(state, agent) {
|
|
|
380
399
|
`);
|
|
381
400
|
}
|
|
382
401
|
function buildObserverPrompt(state, observer) {
|
|
383
|
-
const observerPrompt = getConfig().defaultObserverPrompt;
|
|
402
|
+
const observerPrompt = state.observerPrompt ?? getConfig().defaultObserverPrompt;
|
|
384
403
|
if (observer === "built-in")
|
|
385
404
|
return observerPrompt;
|
|
386
405
|
return `You are an impartial roundtable observer.
|
|
387
|
-
` + `Your role: ${observer}.
|
|
406
|
+
` + `Your role: ${observer}.
|
|
388
407
|
|
|
389
408
|
` + observerPrompt;
|
|
390
409
|
}
|
|
@@ -393,7 +412,10 @@ function buildObserverPrompt(state, observer) {
|
|
|
393
412
|
async function startNewRoundtable(ctx, args, toolCtx) {
|
|
394
413
|
const agents = args.agents;
|
|
395
414
|
const newSession = await ctx.client.session.create({
|
|
396
|
-
body: {
|
|
415
|
+
body: {
|
|
416
|
+
title: generateDefaultTitle({ ...args, agents }),
|
|
417
|
+
parentID: toolCtx.sessionID
|
|
418
|
+
}
|
|
397
419
|
});
|
|
398
420
|
const sessionID = newSession.data.id;
|
|
399
421
|
const parentSessionID = toolCtx.sessionID;
|
|
@@ -411,7 +433,8 @@ async function startNewRoundtable(ctx, args, toolCtx) {
|
|
|
411
433
|
errors: [],
|
|
412
434
|
createdAt: Date.now(),
|
|
413
435
|
currentGeneration: 0,
|
|
414
|
-
userInterjections: []
|
|
436
|
+
userInterjections: [],
|
|
437
|
+
observerPrompt: args.observerPrompt
|
|
415
438
|
};
|
|
416
439
|
states.set(sessionID, state);
|
|
417
440
|
try {
|
|
@@ -423,10 +446,20 @@ async function startNewRoundtable(ctx, args, toolCtx) {
|
|
|
423
446
|
noReply: true,
|
|
424
447
|
parts: [{
|
|
425
448
|
type: "text",
|
|
426
|
-
text:
|
|
449
|
+
text: `⚙ Roundtable started — #${sessionID} • ${agents.join(" → ")} • ${args.rounds} round(s)`
|
|
427
450
|
}]
|
|
428
451
|
}
|
|
429
452
|
});
|
|
453
|
+
await ctx.client.session.prompt({
|
|
454
|
+
path: { id: sessionID },
|
|
455
|
+
body: {
|
|
456
|
+
noReply: true,
|
|
457
|
+
parts: [{ type: "text", text: `⚙ Parent: #${parentSessionID}` }]
|
|
458
|
+
}
|
|
459
|
+
});
|
|
460
|
+
if (getConfig().navigation === "auto") {
|
|
461
|
+
await navigateToSession(ctx, sessionID, parentSessionID);
|
|
462
|
+
}
|
|
430
463
|
await ctx.client.tui.showToast({
|
|
431
464
|
body: {
|
|
432
465
|
message: `Roundtable started in #${sessionID} (${agents.join(" → ")} · ${args.rounds} round(s))`,
|
|
@@ -484,10 +517,13 @@ async function sendToAgent(ctx, state) {
|
|
|
484
517
|
}
|
|
485
518
|
}
|
|
486
519
|
async function updateSessionTitle(ctx, state) {
|
|
487
|
-
const summary = state.prompt.length >
|
|
520
|
+
const summary = state.prompt.length > 40 ? state.prompt.slice(0, 37) + "..." : state.prompt;
|
|
521
|
+
const agentList = state.agents.join("→");
|
|
522
|
+
const roundInfo = `R${state.currentRound + 1}/${state.totalRounds}`;
|
|
523
|
+
const title = `⚡ "${summary}" · ${agentList} (${roundInfo} · ↑ #${state.parentSessionID})`;
|
|
488
524
|
await ctx.client.session.update({
|
|
489
525
|
path: { id: state.sessionID },
|
|
490
|
-
body: { title
|
|
526
|
+
body: { title }
|
|
491
527
|
});
|
|
492
528
|
}
|
|
493
529
|
async function sendObserverPrompt(ctx, state) {
|
|
@@ -533,14 +569,17 @@ async function finalizeRoundtable(ctx, state) {
|
|
|
533
569
|
pendingResults.delete(sessionID);
|
|
534
570
|
}
|
|
535
571
|
await injectRoundtableDelimiter(ctx, sessionID);
|
|
536
|
-
const shortPrompt = state.prompt.length >
|
|
572
|
+
const shortPrompt = state.prompt.length > 40 ? state.prompt.slice(0, 37) + "..." : state.prompt;
|
|
537
573
|
await ctx.client.session.update({
|
|
538
574
|
path: { id: sessionID },
|
|
539
|
-
body: { title:
|
|
575
|
+
body: { title: `⚡ "${shortPrompt}" · ${state.agents.join("→")} ✓` }
|
|
540
576
|
});
|
|
541
577
|
try {
|
|
542
578
|
await saveStateFile(state);
|
|
543
579
|
} catch {}
|
|
580
|
+
if (getConfig().navigation === "auto") {
|
|
581
|
+
await navigateToSession(ctx, state.parentSessionID, sessionID);
|
|
582
|
+
}
|
|
544
583
|
await ctx.client.tui.showToast({
|
|
545
584
|
body: { message: "Roundtable concluded", variant: "success" }
|
|
546
585
|
});
|
|
@@ -845,7 +884,8 @@ async function extendRoundtable(ctx, args, _toolCtx) {
|
|
|
845
884
|
errors: [...originalState.errors],
|
|
846
885
|
createdAt: Date.now(),
|
|
847
886
|
currentGeneration: 0,
|
|
848
|
-
userInterjections: [...originalState.userInterjections ?? []]
|
|
887
|
+
userInterjections: [...originalState.userInterjections ?? []],
|
|
888
|
+
observerPrompt: args.observerPrompt ?? originalState.observerPrompt
|
|
849
889
|
};
|
|
850
890
|
states.set(sessionID, newState);
|
|
851
891
|
try {
|
|
@@ -861,7 +901,7 @@ async function extendRoundtable(ctx, args, _toolCtx) {
|
|
|
861
901
|
noReply: true,
|
|
862
902
|
parts: [{
|
|
863
903
|
type: "text",
|
|
864
|
-
text:
|
|
904
|
+
text: `⚙ Roundtable extended — #${sessionID} • +${args.rounds} round(s)`
|
|
865
905
|
}]
|
|
866
906
|
}
|
|
867
907
|
});
|
|
@@ -945,7 +985,8 @@ var RoundtablePlugin = async (ctx) => {
|
|
|
945
985
|
rounds: tool.schema.number().min(1).max(50).describe("Number of complete rounds (each round = all agents speak once). " + "Default: 1. Max: 50. For complex topics with 2+ rounds, include per-round focus " + "instructions in the prompt parameter so all agents see the agenda."),
|
|
946
986
|
observer: tool.schema.string().optional().describe("Agent name for final consolidation. The observer does not debate — it " + "summarizes after all rounds. Omit to use the built-in observer."),
|
|
947
987
|
sessionID: tool.schema.string().optional().describe("Session ID (format: ses_xxxx) from a previous roundtable call to " + "continue a concluded debate. Omit this parameter and pass agents + " + "prompt to start a fresh debate."),
|
|
948
|
-
title: tool.schema.string().optional().describe("Custom title for the session (max 200 chars). If omitted, auto-generated " + 'as "(Roundtable) - {first 80 chars of prompt, truncated at word boundary}".')
|
|
988
|
+
title: tool.schema.string().optional().describe("Custom title for the session (max 200 chars). If omitted, auto-generated " + 'as "(Roundtable) - {first 80 chars of prompt, truncated at word boundary}".'),
|
|
989
|
+
observerPrompt: tool.schema.string().optional().describe("Override the default observer consolidation prompt. Use this to control " + "the format and focus of the final summary — e.g., ask the observer to " + "save a detailed report to file, focus on technical decisions only, " + "output as JSON, extract action items, etc. " + "If omitted, the default observer prompt is used (executive summary).")
|
|
949
990
|
},
|
|
950
991
|
async execute(args, toolCtx) {
|
|
951
992
|
try {
|
|
@@ -1002,6 +1043,22 @@ var RoundtablePlugin = async (ctx) => {
|
|
|
1002
1043
|
return "Error: Could not fetch agent list. The server might not be ready.";
|
|
1003
1044
|
}
|
|
1004
1045
|
}
|
|
1046
|
+
}),
|
|
1047
|
+
active_roundtables: tool({
|
|
1048
|
+
description: "Lists all active roundtables with their status. " + "Each entry shows session ID, agents, current round, and phase. " + "Returns clickable session IDs that can be used to navigate.",
|
|
1049
|
+
args: {},
|
|
1050
|
+
async execute() {
|
|
1051
|
+
const active = [];
|
|
1052
|
+
for (const [sid, s] of states) {
|
|
1053
|
+
const status = s.phase === "active" ? "debating" : s.phase === "observing" ? "consolidating" : s.phase === "done" ? "concluded" : s.phase;
|
|
1054
|
+
active.push(`- #${sid} · ${s.agents.join("→")} (R${s.currentRound + 1}/${s.totalRounds}) · ${status}`);
|
|
1055
|
+
}
|
|
1056
|
+
if (active.length === 0)
|
|
1057
|
+
return "No active roundtables.";
|
|
1058
|
+
return `Active roundtables:
|
|
1059
|
+
${active.join(`
|
|
1060
|
+
`)}`;
|
|
1061
|
+
}
|
|
1005
1062
|
})
|
|
1006
1063
|
}
|
|
1007
1064
|
};
|
|
@@ -1010,5 +1067,5 @@ export {
|
|
|
1010
1067
|
RoundtablePlugin
|
|
1011
1068
|
};
|
|
1012
1069
|
|
|
1013
|
-
//# debugId=
|
|
1070
|
+
//# debugId=C8BED17810CFAA4D64756E2164756E21
|
|
1014
1071
|
//# sourceMappingURL=index.js.map
|