@dmsdc-ai/aigentry-deliberation 0.0.22 → 0.0.24
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 +58 -0
- package/index.js +29 -3
- package/package.json +2 -1
package/README.md
CHANGED
|
@@ -17,6 +17,12 @@ MCP Deliberation Server — Multi-session AI deliberation with smart speaker ord
|
|
|
17
17
|
- **Cross-platform**: macOS (tmux + Terminal.app), Windows (Windows Terminal), Linux
|
|
18
18
|
- **Obsidian archiving**: Auto-archive deliberation results to Obsidian vault
|
|
19
19
|
- **Session monitoring**: Real-time tmux/terminal monitoring
|
|
20
|
+
- **Vote enforcement**: Automatic [AGREE]/[DISAGREE]/[CONDITIONAL] vote marker requirement
|
|
21
|
+
- **Dynamic CLI timeout**: Smart cold-start handling (180s first turn, 120s subsequent)
|
|
22
|
+
- **Runtime logging**: Session lifecycle event logging for observability
|
|
23
|
+
- **Resilient browser automation**: 5-stage degradation state machine with 60s SLO
|
|
24
|
+
- **Model routing**: Dynamic per-provider model selection based on prompt analysis
|
|
25
|
+
- **Role drift detection**: Structural heading markers + keyword analysis for accurate role inference
|
|
20
26
|
|
|
21
27
|
## Installation
|
|
22
28
|
|
|
@@ -121,6 +127,34 @@ Claude Code, Codex CLI, Gemini CLI의 MCP 설정을 자동 점검하고 문제
|
|
|
121
127
|
| `researcher` | Data, benchmarks, references |
|
|
122
128
|
| `free` | No role constraint (default) |
|
|
123
129
|
|
|
130
|
+
### Supported CLI Speakers
|
|
131
|
+
|
|
132
|
+
| CLI | Command | Status |
|
|
133
|
+
|-----|---------|--------|
|
|
134
|
+
| Claude Code | `claude` | ✅ Tested |
|
|
135
|
+
| Codex CLI | `codex` | ✅ Tested |
|
|
136
|
+
| Gemini CLI | `gemini` | ✅ Tested |
|
|
137
|
+
| Aider | `aider` | 🔧 Supported |
|
|
138
|
+
| Cursor Agent | `cursor` | 🔧 Supported |
|
|
139
|
+
| OpenCode | `opencode` | 🔧 Supported |
|
|
140
|
+
| Continue | `continue` | 🔧 Supported |
|
|
141
|
+
|
|
142
|
+
### Supported Browser LLMs
|
|
143
|
+
|
|
144
|
+
| Provider | Transport | Status |
|
|
145
|
+
|----------|-----------|--------|
|
|
146
|
+
| ChatGPT | CDP / Clipboard | ✅ Tested |
|
|
147
|
+
| Claude Web | CDP / Clipboard | ✅ Tested |
|
|
148
|
+
| Gemini Web | CDP / Clipboard | ✅ Tested |
|
|
149
|
+
| DeepSeek | CDP / Clipboard | ✅ Tested |
|
|
150
|
+
| Qwen | CDP / Clipboard | ✅ Tested |
|
|
151
|
+
| Poe | CDP / Clipboard | ✅ Tested |
|
|
152
|
+
| Copilot | CDP / Clipboard | 🔧 Supported |
|
|
153
|
+
| Perplexity | CDP / Clipboard | 🔧 Supported |
|
|
154
|
+
| Mistral | CDP / Clipboard | 🔧 Supported |
|
|
155
|
+
| Grok | CDP / Clipboard | 🔧 Supported |
|
|
156
|
+
| HuggingChat | CDP / Clipboard | 🔧 Supported |
|
|
157
|
+
|
|
124
158
|
### deliberation-gate (Superpowers Integration)
|
|
125
159
|
|
|
126
160
|
Inserts multi-AI verification gates at key [superpowers](https://github.com/obra/superpowers) workflow decision points.
|
|
@@ -143,6 +177,30 @@ cp skills/deliberation-gate/SKILL.md ~/.claude/skills/deliberation-gate/SKILL.md
|
|
|
143
177
|
|
|
144
178
|
**RFC:** [Prerequisites header for tool-dependent skills](https://github.com/obra/superpowers/issues/589)
|
|
145
179
|
|
|
180
|
+
## What's New
|
|
181
|
+
|
|
182
|
+
### v0.0.24
|
|
183
|
+
- **Role inference**: Heading marker weight increased from +5 to +8, added critic(검증/평가/Review) and researcher(데이터/Data) patterns to reduce false positives
|
|
184
|
+
- **Logging payload**: TURN log includes `suggested_role`, `role_drift`; CLI_TURN log includes `prior_turns`, `effective_timeout`
|
|
185
|
+
- **Vote marker warning**: WARN-level `INVALID_TURN` logged when response lacks [AGREE]/[DISAGREE]/[CONDITIONAL] markers
|
|
186
|
+
- **Auto-deploy**: `postversion` hook auto-installs to MCP server path after `npm version`
|
|
187
|
+
|
|
188
|
+
### v0.0.23
|
|
189
|
+
- **Vote enforcement**: Turn prompts now require [AGREE]/[DISAGREE]/[CONDITIONAL] markers for reliable consensus measurement
|
|
190
|
+
- **Dynamic CLI timeout**: First CLI invocation gets 180s (cold-start buffer), subsequent turns use default 120s
|
|
191
|
+
- **Runtime logging**: INFO-level lifecycle logging (SESSION_CREATED, TURN, CLI_TURN, SYNTHESIZED) to `runtime.log`
|
|
192
|
+
- **Role inference improvement**: Structural heading markers (e.g., `## 조사 결과` → researcher) with +5 weight prevent false role drift detection
|
|
193
|
+
|
|
194
|
+
### v0.0.22
|
|
195
|
+
- **Security**: CDP `--remote-allow-origins` restricted to `127.0.0.1:9222` (was `*`)
|
|
196
|
+
- **Security**: Observer CORS restricted to localhost allowlist, server bound to `127.0.0.1`
|
|
197
|
+
- **Performance**: Async sleep for Chrome CDP initialization (was blocking event loop)
|
|
198
|
+
- **Bug fix**: Fabrication guard uses `detectCallerSpeaker()` instead of hardcoded `"claude"`
|
|
199
|
+
- **Bug fix**: CLI reviewer uses per-CLI invocation flags via `CLI_INVOCATION_HINTS`
|
|
200
|
+
- **Bug fix**: Windows monitor state directory path corrected
|
|
201
|
+
- **Memory**: SSE client Map cleanup on disconnect prevents memory leak
|
|
202
|
+
- **Code quality**: Removed unreachable dead code in browser-control-port
|
|
203
|
+
|
|
146
204
|
## aigentry Ecosystem
|
|
147
205
|
|
|
148
206
|
aigentry-deliberation is one component of the unified aigentry platform. All packages work together to make AI decisions transparent and auditable.
|
package/index.js
CHANGED
|
@@ -218,12 +218,25 @@ const ROLE_KEYWORDS = {
|
|
|
218
218
|
researcher: /사례|데이터|연구|벤치마크|비교|논문|참고/,
|
|
219
219
|
};
|
|
220
220
|
|
|
221
|
+
const ROLE_HEADING_MARKERS = {
|
|
222
|
+
critic: /^##?\s*(Critic|비판|약점|심각도|위험\s*분석|검증|평가|Review)/m,
|
|
223
|
+
implementer: /^##?\s*(코드\s*스케치|구현|Implementation|제안\s*코드)/m,
|
|
224
|
+
mediator: /^##?\s*(합의|종합|중재|Consensus|Mediation)/m,
|
|
225
|
+
researcher: /^##?\s*(조사\s*결과|비교\s*분석|Research|사례\s*연구|근거|데이터|Data)/m,
|
|
226
|
+
};
|
|
227
|
+
|
|
221
228
|
function inferSuggestedRole(text) {
|
|
222
229
|
const scores = {};
|
|
223
230
|
for (const [role, pattern] of Object.entries(ROLE_KEYWORDS)) {
|
|
224
231
|
const matches = (text.match(new RegExp(pattern, "g")) || []).length;
|
|
225
232
|
if (matches > 0) scores[role] = matches;
|
|
226
233
|
}
|
|
234
|
+
// Structural heading markers get extra weight (equivalent to 5 keyword matches)
|
|
235
|
+
for (const [role, pattern] of Object.entries(ROLE_HEADING_MARKERS)) {
|
|
236
|
+
if (pattern.test(text)) {
|
|
237
|
+
scores[role] = (scores[role] || 0) + 8;
|
|
238
|
+
}
|
|
239
|
+
}
|
|
227
240
|
if (Object.keys(scores).length === 0) return "free";
|
|
228
241
|
return Object.entries(scores).sort((a, b) => b[1] - a[1])[0][0];
|
|
229
242
|
}
|
|
@@ -2237,6 +2250,7 @@ ${recent}
|
|
|
2237
2250
|
[response_rule]
|
|
2238
2251
|
- 위 토론 맥락을 반영해 ${speaker}의 이번 턴 응답만 작성
|
|
2239
2252
|
- 마크다운 본문만 출력 (불필요한 머리말/꼬리말 금지)${speakerRole !== "free" ? `\n- 배정된 역할(${speakerRole})의 관점에서 분석하고 응답` : ""}
|
|
2253
|
+
- 응답 마지막에 반드시 [AGREE], [DISAGREE], 또는 [CONDITIONAL: 사유] 중 하나를 포함
|
|
2240
2254
|
[/response_rule]
|
|
2241
2255
|
[/deliberation_turn_request]
|
|
2242
2256
|
`;
|
|
@@ -2290,6 +2304,9 @@ function submitDeliberationTurn({ session_id, speaker, content, turn_id, channel
|
|
|
2290
2304
|
}
|
|
2291
2305
|
|
|
2292
2306
|
const votes = parseVotes(content);
|
|
2307
|
+
if (votes.length === 0) {
|
|
2308
|
+
appendRuntimeLog("WARN", `INVALID_TURN: ${state.id} | R${state.current_round} | speaker: ${normalizedSpeaker} | reason: no_vote_marker`);
|
|
2309
|
+
}
|
|
2293
2310
|
const suggestedRole = inferSuggestedRole(content);
|
|
2294
2311
|
const assignedRole = (state.speaker_roles || {})[normalizedSpeaker] || "free";
|
|
2295
2312
|
const roleDrift = assignedRole !== "free" && suggestedRole !== "free" && assignedRole !== suggestedRole;
|
|
@@ -2305,6 +2322,7 @@ function submitDeliberationTurn({ session_id, speaker, content, turn_id, channel
|
|
|
2305
2322
|
suggested_next_role: suggestedRole !== "free" ? suggestedRole : undefined,
|
|
2306
2323
|
role_drift: roleDrift || undefined,
|
|
2307
2324
|
});
|
|
2325
|
+
appendRuntimeLog("INFO", `TURN: ${state.id} | R${state.current_round} | speaker: ${normalizedSpeaker} | votes: ${votes.length > 0 ? votes.map(v => v.vote).join(",") : "none"} | channel: ${channel_used || "respond"} | suggested_role: ${suggestedRole} | role_drift: ${roleDrift || false}`);
|
|
2308
2326
|
|
|
2309
2327
|
state.current_speaker = selectNextSpeaker(state);
|
|
2310
2328
|
|
|
@@ -2611,6 +2629,7 @@ server.tool(
|
|
|
2611
2629
|
return ` - \`${p.speaker}\`: ${transport} (${p.type})`;
|
|
2612
2630
|
}).join("\n");
|
|
2613
2631
|
|
|
2632
|
+
appendRuntimeLog("INFO", `SESSION_CREATED: ${sessionId} | topic: ${topic.slice(0, 60)} | speakers: ${speakerOrder.join(",")} | rounds: ${rounds}`);
|
|
2614
2633
|
return {
|
|
2615
2634
|
content: [{
|
|
2616
2635
|
type: "text",
|
|
@@ -2989,6 +3008,10 @@ server.tool(
|
|
|
2989
3008
|
}] };
|
|
2990
3009
|
}
|
|
2991
3010
|
|
|
3011
|
+
// Dynamic timeout: first turn gets extra time for cold-start
|
|
3012
|
+
const speakerPriorTurns = state.log.filter(e => e.speaker === speaker).length;
|
|
3013
|
+
const effectiveTimeout = speakerPriorTurns === 0 ? Math.max(timeout_sec, 180) : timeout_sec;
|
|
3014
|
+
|
|
2992
3015
|
const hint = CLI_INVOCATION_HINTS[speaker];
|
|
2993
3016
|
if (!hint) {
|
|
2994
3017
|
return { content: [{ type: "text", text: `speaker "${speaker}"에 대한 CLI 호출 정보가 없습니다. CLI_INVOCATION_HINTS에 등록되지 않은 speaker입니다.` }] };
|
|
@@ -3039,8 +3062,8 @@ server.tool(
|
|
|
3039
3062
|
|
|
3040
3063
|
const timer = setTimeout(() => {
|
|
3041
3064
|
child.kill("SIGTERM");
|
|
3042
|
-
reject(new Error(`CLI 타임아웃 (${
|
|
3043
|
-
},
|
|
3065
|
+
reject(new Error(`CLI 타임아웃 (${effectiveTimeout}초)`));
|
|
3066
|
+
}, effectiveTimeout * 1000);
|
|
3044
3067
|
|
|
3045
3068
|
child.stdout.on("data", (data) => { stdout += data.toString(); });
|
|
3046
3069
|
child.stderr.on("data", (data) => { stderr += data.toString(); });
|
|
@@ -3072,6 +3095,7 @@ server.tool(
|
|
|
3072
3095
|
});
|
|
3073
3096
|
|
|
3074
3097
|
const elapsedMs = Date.now() - startTime;
|
|
3098
|
+
appendRuntimeLog("INFO", `CLI_TURN: ${resolved} | speaker: ${speaker} | cli: ${hint.cmd} | elapsed: ${elapsedMs}ms | response_len: ${response.length} | prior_turns: ${speakerPriorTurns} | effective_timeout: ${effectiveTimeout}s`);
|
|
3075
3099
|
|
|
3076
3100
|
if (!response) {
|
|
3077
3101
|
return { content: [{ type: "text", text: `⚠️ CLI "${speaker}"가 빈 응답을 반환했습니다.` }] };
|
|
@@ -3233,6 +3257,8 @@ server.tool(
|
|
|
3233
3257
|
return lockedResult;
|
|
3234
3258
|
}
|
|
3235
3259
|
|
|
3260
|
+
appendRuntimeLog("INFO", `SYNTHESIZED: ${resolved} | turns: ${state.log.length} | rounds: ${state.max_rounds}`);
|
|
3261
|
+
|
|
3236
3262
|
// 토론 종료 즉시 모니터 터미널(물리 Terminal 포함) 강제 종료
|
|
3237
3263
|
closeMonitorTerminal(state.id, getSessionWindowIds(state));
|
|
3238
3264
|
|
|
@@ -3758,4 +3784,4 @@ if (__entryFile && path.resolve(__currentFile) === __entryFile) {
|
|
|
3758
3784
|
}
|
|
3759
3785
|
|
|
3760
3786
|
// ── Test exports (used by vitest) ──
|
|
3761
|
-
export { selectNextSpeaker, loadRolePrompt, inferSuggestedRole, parseVotes, ROLE_KEYWORDS, loadRolePresets, applyRolePreset, detectDegradationLevels, formatDegradationReport, DEGRADATION_TIERS };
|
|
3787
|
+
export { selectNextSpeaker, loadRolePrompt, inferSuggestedRole, parseVotes, ROLE_KEYWORDS, ROLE_HEADING_MARKERS, loadRolePresets, applyRolePreset, detectDegradationLevels, formatDegradationReport, DEGRADATION_TIERS };
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@dmsdc-ai/aigentry-deliberation",
|
|
3
|
-
"version": "0.0.
|
|
3
|
+
"version": "0.0.24",
|
|
4
4
|
"description": "MCP Deliberation Server — Multi-session AI deliberation with smart speaker ordering and persona roles",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"license": "MIT",
|
|
@@ -48,6 +48,7 @@
|
|
|
48
48
|
"test": "vitest run",
|
|
49
49
|
"test:watch": "vitest",
|
|
50
50
|
"prepublishOnly": "vitest run",
|
|
51
|
+
"postversion": "node install.js",
|
|
51
52
|
"release:patch": "npm version patch && git push && git push --tags",
|
|
52
53
|
"release:minor": "npm version minor && git push && git push --tags",
|
|
53
54
|
"release:major": "npm version major && git push && git push --tags"
|