@lanjak/council 0.0.0-stage → 0.5.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/README.md +512 -2
- package/dist/artifacts.d.ts +24 -0
- package/dist/artifacts.js +227 -0
- package/dist/artifacts.js.map +1 -0
- package/dist/blocks.d.ts +12 -0
- package/dist/blocks.js +197 -0
- package/dist/blocks.js.map +1 -0
- package/dist/chairman.d.ts +7 -0
- package/dist/chairman.js +51 -0
- package/dist/chairman.js.map +1 -0
- package/dist/cli.d.ts +2 -0
- package/dist/cli.js +109 -0
- package/dist/cli.js.map +1 -0
- package/dist/commands/debate.d.ts +15 -0
- package/dist/commands/debate.js +172 -0
- package/dist/commands/debate.js.map +1 -0
- package/dist/commands/home.d.ts +1 -0
- package/dist/commands/home.js +27 -0
- package/dist/commands/home.js.map +1 -0
- package/dist/commands/hook.d.ts +3 -0
- package/dist/commands/hook.js +138 -0
- package/dist/commands/hook.js.map +1 -0
- package/dist/commands/plan.d.ts +6 -0
- package/dist/commands/plan.js +23 -0
- package/dist/commands/plan.js.map +1 -0
- package/dist/commands/review.d.ts +18 -0
- package/dist/commands/review.js +37 -0
- package/dist/commands/review.js.map +1 -0
- package/dist/commands/setup.d.ts +1 -0
- package/dist/commands/setup.js +23 -0
- package/dist/commands/setup.js.map +1 -0
- package/dist/config.d.ts +17 -0
- package/dist/config.js +101 -0
- package/dist/config.js.map +1 -0
- package/dist/council.d.ts +3 -0
- package/dist/council.js +61 -0
- package/dist/council.js.map +1 -0
- package/dist/debate/loop.d.ts +28 -0
- package/dist/debate/loop.js +188 -0
- package/dist/debate/loop.js.map +1 -0
- package/dist/debate/prompts.d.ts +10 -0
- package/dist/debate/prompts.js +47 -0
- package/dist/debate/prompts.js.map +1 -0
- package/dist/debate/render.d.ts +22 -0
- package/dist/debate/render.js +112 -0
- package/dist/debate/render.js.map +1 -0
- package/dist/debate/session.d.ts +7 -0
- package/dist/debate/session.js +85 -0
- package/dist/debate/session.js.map +1 -0
- package/dist/errors.d.ts +5 -0
- package/dist/errors.js +18 -0
- package/dist/errors.js.map +1 -0
- package/dist/exit.d.ts +7 -0
- package/dist/exit.js +13 -0
- package/dist/exit.js.map +1 -0
- package/dist/hooks/gate.d.ts +12 -0
- package/dist/hooks/gate.js +41 -0
- package/dist/hooks/gate.js.map +1 -0
- package/dist/hooks/payload.d.ts +8 -0
- package/dist/hooks/payload.js +63 -0
- package/dist/hooks/payload.js.map +1 -0
- package/dist/hooks/state.d.ts +6 -0
- package/dist/hooks/state.js +73 -0
- package/dist/hooks/state.js.map +1 -0
- package/dist/index.d.ts +16 -0
- package/dist/index.js +16 -0
- package/dist/index.js.map +1 -0
- package/dist/input.d.ts +14 -0
- package/dist/input.js +30 -0
- package/dist/input.js.map +1 -0
- package/dist/output.d.ts +3 -0
- package/dist/output.js +80 -0
- package/dist/output.js.map +1 -0
- package/dist/prompts.d.ts +3 -0
- package/dist/prompts.js +48 -0
- package/dist/prompts.js.map +1 -0
- package/dist/providers/anthropic.d.ts +12 -0
- package/dist/providers/anthropic.js +98 -0
- package/dist/providers/anthropic.js.map +1 -0
- package/dist/providers/base.d.ts +35 -0
- package/dist/providers/base.js +7 -0
- package/dist/providers/base.js.map +1 -0
- package/dist/providers/constants.d.ts +2 -0
- package/dist/providers/constants.js +11 -0
- package/dist/providers/constants.js.map +1 -0
- package/dist/providers/index.d.ts +6 -0
- package/dist/providers/index.js +20 -0
- package/dist/providers/index.js.map +1 -0
- package/dist/providers/openai-compatible.d.ts +12 -0
- package/dist/providers/openai-compatible.js +68 -0
- package/dist/providers/openai-compatible.js.map +1 -0
- package/dist/runners/plan.d.ts +14 -0
- package/dist/runners/plan.js +43 -0
- package/dist/runners/plan.js.map +1 -0
- package/dist/runners/review.d.ts +14 -0
- package/dist/runners/review.js +45 -0
- package/dist/runners/review.js.map +1 -0
- package/dist/stdin.d.ts +9 -0
- package/dist/stdin.js +51 -0
- package/dist/stdin.js.map +1 -0
- package/dist/types.d.ts +114 -0
- package/dist/types.js +2 -0
- package/dist/types.js.map +1 -0
- package/dist/verdict.d.ts +2 -0
- package/dist/verdict.js +12 -0
- package/dist/verdict.js.map +1 -0
- package/package.json +54 -4
- package/skills/council/SKILL.md +82 -0
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"config.js","sourceRoot":"","sources":["../src/config.ts"],"names":[],"mappings":"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"}
|
package/dist/council.js
ADDED
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
import { loadProvider } from './providers/index.js';
|
|
2
|
+
import { parseHardBlocks } from './blocks.js';
|
|
3
|
+
export async function runCouncil(config, request) {
|
|
4
|
+
const promises = request.models.map(async (providerKey) => {
|
|
5
|
+
const providerConfig = config.providers[providerKey];
|
|
6
|
+
if (!providerConfig) {
|
|
7
|
+
return {
|
|
8
|
+
provider: providerKey,
|
|
9
|
+
model: 'unknown',
|
|
10
|
+
status: 'skipped',
|
|
11
|
+
error: { message: `No configuration for provider "${providerKey}"` },
|
|
12
|
+
};
|
|
13
|
+
}
|
|
14
|
+
if (!providerConfig.model) {
|
|
15
|
+
return {
|
|
16
|
+
provider: providerKey,
|
|
17
|
+
model: 'unknown',
|
|
18
|
+
status: 'skipped',
|
|
19
|
+
error: { message: `No model configured for provider "${providerKey}"` },
|
|
20
|
+
};
|
|
21
|
+
}
|
|
22
|
+
if (!providerConfig.apiKey) {
|
|
23
|
+
return {
|
|
24
|
+
provider: providerKey,
|
|
25
|
+
model: providerConfig.model,
|
|
26
|
+
status: 'skipped',
|
|
27
|
+
error: { message: `API key not set for ${providerKey}` },
|
|
28
|
+
};
|
|
29
|
+
}
|
|
30
|
+
const provider = loadProvider(providerKey, providerConfig);
|
|
31
|
+
try {
|
|
32
|
+
const result = await provider.chat({
|
|
33
|
+
prompt: request.prompt,
|
|
34
|
+
system: request.systemPrompt,
|
|
35
|
+
maxTokens: request.maxTokens,
|
|
36
|
+
effort: request.effort,
|
|
37
|
+
model: providerConfig.model,
|
|
38
|
+
});
|
|
39
|
+
return {
|
|
40
|
+
provider: providerKey,
|
|
41
|
+
model: providerConfig.model,
|
|
42
|
+
status: 'success',
|
|
43
|
+
response: result.content,
|
|
44
|
+
reasoning: result.reasoning,
|
|
45
|
+
usage: result.usage,
|
|
46
|
+
...(request.blockKey ? { blockParse: parseHardBlocks(result.content, request.blockKey) } : {}),
|
|
47
|
+
};
|
|
48
|
+
}
|
|
49
|
+
catch (err) {
|
|
50
|
+
const message = err instanceof Error ? err.message : String(err);
|
|
51
|
+
return {
|
|
52
|
+
provider: providerKey,
|
|
53
|
+
model: providerConfig.model,
|
|
54
|
+
status: 'error',
|
|
55
|
+
error: { message },
|
|
56
|
+
};
|
|
57
|
+
}
|
|
58
|
+
});
|
|
59
|
+
return Promise.all(promises);
|
|
60
|
+
}
|
|
61
|
+
//# sourceMappingURL=council.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"council.js","sourceRoot":"","sources":["../src/council.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,YAAY,EAAE,MAAM,sBAAsB,CAAC;AACpD,OAAO,EAAE,eAAe,EAAE,MAAM,aAAa,CAAC;AAI9C,MAAM,CAAC,KAAK,UAAU,UAAU,CAAC,MAAqB,EAAE,OAAuB;IAC7E,MAAM,QAAQ,GAAG,OAAO,CAAC,MAAM,CAAC,GAAG,CAAC,KAAK,EAAE,WAAW,EAAwB,EAAE;QAC9E,MAAM,cAAc,GAAG,MAAM,CAAC,SAAS,CAAC,WAAW,CAAC,CAAC;QAErD,IAAI,CAAC,cAAc,EAAE,CAAC;YACpB,OAAO;gBACL,QAAQ,EAAE,WAAW;gBACrB,KAAK,EAAE,SAAS;gBAChB,MAAM,EAAE,SAAS;gBACjB,KAAK,EAAE,EAAE,OAAO,EAAE,kCAAkC,WAAW,GAAG,EAAE;aACrE,CAAC;QACJ,CAAC;QAED,IAAI,CAAC,cAAc,CAAC,KAAK,EAAE,CAAC;YAC1B,OAAO;gBACL,QAAQ,EAAE,WAAW;gBACrB,KAAK,EAAE,SAAS;gBAChB,MAAM,EAAE,SAAS;gBACjB,KAAK,EAAE,EAAE,OAAO,EAAE,qCAAqC,WAAW,GAAG,EAAE;aACxE,CAAC;QACJ,CAAC;QAED,IAAI,CAAC,cAAc,CAAC,MAAM,EAAE,CAAC;YAC3B,OAAO;gBACL,QAAQ,EAAE,WAAW;gBACrB,KAAK,EAAE,cAAc,CAAC,KAAK;gBAC3B,MAAM,EAAE,SAAS;gBACjB,KAAK,EAAE,EAAE,OAAO,EAAE,uBAAuB,WAAW,EAAE,EAAE;aACzD,CAAC;QACJ,CAAC;QAED,MAAM,QAAQ,GAAG,YAAY,CAAC,WAAW,EAAE,cAAc,CAAC,CAAC;QAE3D,IAAI,CAAC;YACH,MAAM,MAAM,GAAG,MAAM,QAAQ,CAAC,IAAI,CAAC;gBACjC,MAAM,EAAE,OAAO,CAAC,MAAM;gBACtB,MAAM,EAAE,OAAO,CAAC,YAAY;gBAC5B,SAAS,EAAE,OAAO,CAAC,SAAS;gBAC5B,MAAM,EAAE,OAAO,CAAC,MAAM;gBACtB,KAAK,EAAE,cAAc,CAAC,KAAK;aAC5B,CAAC,CAAC;YAEH,OAAO;gBACL,QAAQ,EAAE,WAAW;gBACrB,KAAK,EAAE,cAAc,CAAC,KAAK;gBAC3B,MAAM,EAAE,SAAS;gBACjB,QAAQ,EAAE,MAAM,CAAC,OAAO;gBACxB,SAAS,EAAE,MAAM,CAAC,SAAS;gBAC3B,KAAK,EAAE,MAAM,CAAC,KAAK;gBACnB,GAAG,CAAC,OAAO,CAAC,QAAQ,CAAC,CAAC,CAAC,EAAE,UAAU,EAAE,eAAe,CAAC,MAAM,CAAC,OAAO,EAAE,OAAO,CAAC,QAAQ,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;aAC/F,CAAC;QACJ,CAAC;QAAC,OAAO,GAAG,EAAE,CAAC;YACb,MAAM,OAAO,GAAG,GAAG,YAAY,KAAK,CAAC,CAAC,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC;YACjE,OAAO;gBACL,QAAQ,EAAE,WAAW;gBACrB,KAAK,EAAE,cAAc,CAAC,KAAK;gBAC3B,MAAM,EAAE,OAAO;gBACf,KAAK,EAAE,EAAE,OAAO,EAAE;aACnB,CAAC;QACJ,CAAC;IACH,CAAC,CAAC,CAAC;IAEH,OAAO,OAAO,CAAC,GAAG,CAAC,QAAQ,CAAC,CAAC;AAC/B,CAAC"}
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
import type { CouncilConfig } from '../config.js';
|
|
2
|
+
import type { DebateTurn, RunControls } from '../types.js';
|
|
3
|
+
export declare const CALLER = "caller";
|
|
4
|
+
export interface DebateRunOptions extends RunControls {
|
|
5
|
+
prompt: string;
|
|
6
|
+
models: string[];
|
|
7
|
+
participate: boolean;
|
|
8
|
+
maxRounds: number;
|
|
9
|
+
}
|
|
10
|
+
export interface DebateProgress {
|
|
11
|
+
turns: DebateTurn[];
|
|
12
|
+
status: 'consensus' | 'cap' | 'attrition' | 'awaiting-caller';
|
|
13
|
+
nextTurn?: {
|
|
14
|
+
round: number;
|
|
15
|
+
participant: string;
|
|
16
|
+
order: string[];
|
|
17
|
+
};
|
|
18
|
+
}
|
|
19
|
+
export declare function roundOrder(active: string[], round: number): string[];
|
|
20
|
+
export declare function activeParticipants(participants: string[], turns: DebateTurn[]): string[];
|
|
21
|
+
export declare function runDebate(config: CouncilConfig, opts: DebateRunOptions, resume?: {
|
|
22
|
+
turns: DebateTurn[];
|
|
23
|
+
nextTurn: {
|
|
24
|
+
round: number;
|
|
25
|
+
participant: string;
|
|
26
|
+
order: string[];
|
|
27
|
+
};
|
|
28
|
+
}): Promise<DebateProgress>;
|
|
@@ -0,0 +1,188 @@
|
|
|
1
|
+
import { loadProvider } from '../providers/index.js';
|
|
2
|
+
import { CouncilError } from '../errors.js';
|
|
3
|
+
import { parseVerdict } from '../verdict.js';
|
|
4
|
+
import { formatTranscript, openerPrompt, turnPrompt } from './prompts.js';
|
|
5
|
+
export const CALLER = 'caller';
|
|
6
|
+
export function roundOrder(active, round) {
|
|
7
|
+
const start = (round - 1) % active.length;
|
|
8
|
+
return [...active.slice(start), ...active.slice(0, start)];
|
|
9
|
+
}
|
|
10
|
+
// A participant stays active while its latest recorded turn succeeded.
|
|
11
|
+
// The caller is always active once it has spoken (it cannot error).
|
|
12
|
+
export function activeParticipants(participants, turns) {
|
|
13
|
+
return participants.filter((p) => {
|
|
14
|
+
if (p === CALLER)
|
|
15
|
+
return true;
|
|
16
|
+
const latest = [...turns].reverse().find((t) => t.provider === p);
|
|
17
|
+
return latest === undefined || latest.status === 'success';
|
|
18
|
+
});
|
|
19
|
+
}
|
|
20
|
+
function latestTurn(turns, provider) {
|
|
21
|
+
return [...turns].reverse().find((t) => t.provider === provider);
|
|
22
|
+
}
|
|
23
|
+
function hasConsensus(roster, turns) {
|
|
24
|
+
const active = activeParticipants(roster, turns);
|
|
25
|
+
if (active.length < 2)
|
|
26
|
+
return false;
|
|
27
|
+
return active.every((p) => latestTurn(turns, p)?.verdict === 'agree');
|
|
28
|
+
}
|
|
29
|
+
function checkRoundOneQuorum(round, roster, turns) {
|
|
30
|
+
if (round !== 1)
|
|
31
|
+
return;
|
|
32
|
+
const survivingJudges = activeParticipants(roster, turns).filter((p) => p !== CALLER);
|
|
33
|
+
if (survivingJudges.length < 2) {
|
|
34
|
+
throw new CouncilError('Fewer than 2 judges survived round 1', 'NO_QUORUM');
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
export async function runDebate(config, opts, resume) {
|
|
38
|
+
const roster = opts.participate ? [...opts.models, CALLER] : [...opts.models];
|
|
39
|
+
const turns = resume ? [...resume.turns] : [];
|
|
40
|
+
let round = resume ? resume.nextTurn.round : 1;
|
|
41
|
+
// Resuming can land exactly on a round boundary: resume.nextTurn.round is
|
|
42
|
+
// one past the last fully-recorded round (e.g. the caller turn that just
|
|
43
|
+
// completed round 1 was appended, and nextTurn now points at round 2's
|
|
44
|
+
// first speaker). In that case the completed prior round's consensus (and
|
|
45
|
+
// cap) must be evaluated before any new turn runs, since no turn in the
|
|
46
|
+
// new round has been asked for yet - the "round has just completed" check
|
|
47
|
+
// that normally runs at the bottom of the loop body never got to run for
|
|
48
|
+
// that prior round in this process.
|
|
49
|
+
if (resume) {
|
|
50
|
+
const priorRound = resume.nextTurn.round - 1;
|
|
51
|
+
const roundIsComplete = priorRound >= 1 &&
|
|
52
|
+
!turns.some((t) => t.round === resume.nextTurn.round) &&
|
|
53
|
+
turns.some((t) => t.round === priorRound);
|
|
54
|
+
if (roundIsComplete) {
|
|
55
|
+
checkRoundOneQuorum(priorRound, roster, turns);
|
|
56
|
+
if (hasConsensus(roster, turns)) {
|
|
57
|
+
return { turns, status: 'consensus' };
|
|
58
|
+
}
|
|
59
|
+
const active = activeParticipants(roster, turns);
|
|
60
|
+
if (active.length < 2)
|
|
61
|
+
return { turns, status: 'attrition' };
|
|
62
|
+
if (priorRound >= opts.maxRounds)
|
|
63
|
+
return { turns, status: 'cap' };
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
while (round <= opts.maxRounds) {
|
|
67
|
+
const active = activeParticipants(roster, turns);
|
|
68
|
+
if (active.length < 2)
|
|
69
|
+
return { turns, status: 'attrition' };
|
|
70
|
+
// The round's speaking order is frozen once, at round start, from the
|
|
71
|
+
// actives at that moment. A mid-round resume (turns already recorded for
|
|
72
|
+
// this round, e.g. the caller's turn that just triggered this call)
|
|
73
|
+
// must replay that same frozen order rather than recompute it from the
|
|
74
|
+
// current active set - attrition partway through the round (a judge
|
|
75
|
+
// erroring before the caller's slot) must never shift who speaks after
|
|
76
|
+
// the resume point. A resume that lands on a fresh round (no turns
|
|
77
|
+
// recorded for it yet) computes the order anew from actives at that
|
|
78
|
+
// round's start, same as a non-resumed round.
|
|
79
|
+
let order;
|
|
80
|
+
let startIdx = 0;
|
|
81
|
+
if (resume && round === resume.nextTurn.round && turns.some((t) => t.round === round)) {
|
|
82
|
+
order = resume.nextTurn.order;
|
|
83
|
+
startIdx = Math.max(order.indexOf(resume.nextTurn.participant), 0);
|
|
84
|
+
}
|
|
85
|
+
else {
|
|
86
|
+
order = roundOrder(active, round);
|
|
87
|
+
}
|
|
88
|
+
for (let i = startIdx; i < order.length; i++) {
|
|
89
|
+
const participant = order[i];
|
|
90
|
+
// Skip anyone who already has a turn this round (resume replays a partial round)
|
|
91
|
+
// or who is no longer active (an errored judge cannot speak, even if the frozen
|
|
92
|
+
// order still lists it) - a healthy judge, by contrast, must never be skipped.
|
|
93
|
+
if (turns.some((t) => t.round === round && t.provider === participant))
|
|
94
|
+
continue;
|
|
95
|
+
if (participant !== CALLER && !active.includes(participant))
|
|
96
|
+
continue;
|
|
97
|
+
if (participant === CALLER) {
|
|
98
|
+
// CALLER is always last in the roster, so every judge has already
|
|
99
|
+
// taken its round-1 turn by the time we reach it here. Enforce
|
|
100
|
+
// quorum now - otherwise, with participate:true, this check would
|
|
101
|
+
// never run at all: the loop returns before ever reaching the
|
|
102
|
+
// post-loop check below.
|
|
103
|
+
checkRoundOneQuorum(round, roster, turns);
|
|
104
|
+
return { turns, status: 'awaiting-caller', nextTurn: { round, participant: CALLER, order } };
|
|
105
|
+
}
|
|
106
|
+
turns.push(await judgeTurn(config, opts, roster.length, round, participant, turns));
|
|
107
|
+
}
|
|
108
|
+
checkRoundOneQuorum(round, roster, turns);
|
|
109
|
+
const nowActive = activeParticipants(roster, turns);
|
|
110
|
+
if (nowActive.length < 2)
|
|
111
|
+
return { turns, status: 'attrition' };
|
|
112
|
+
if (hasConsensus(roster, turns))
|
|
113
|
+
return { turns, status: 'consensus' };
|
|
114
|
+
round += 1;
|
|
115
|
+
}
|
|
116
|
+
return { turns, status: 'cap' };
|
|
117
|
+
}
|
|
118
|
+
async function judgeTurn(config, opts, judgeCount, round, providerKey, priorTurns) {
|
|
119
|
+
const providerConfig = config.providers[providerKey];
|
|
120
|
+
if (!providerConfig) {
|
|
121
|
+
return {
|
|
122
|
+
round,
|
|
123
|
+
provider: providerKey,
|
|
124
|
+
model: 'unknown',
|
|
125
|
+
status: 'skipped',
|
|
126
|
+
error: { message: `No configuration for provider "${providerKey}"` },
|
|
127
|
+
};
|
|
128
|
+
}
|
|
129
|
+
if (!providerConfig.model) {
|
|
130
|
+
return {
|
|
131
|
+
round,
|
|
132
|
+
provider: providerKey,
|
|
133
|
+
model: 'unknown',
|
|
134
|
+
status: 'skipped',
|
|
135
|
+
error: { message: `No model configured for provider "${providerKey}"` },
|
|
136
|
+
};
|
|
137
|
+
}
|
|
138
|
+
if (!providerConfig.apiKey) {
|
|
139
|
+
return {
|
|
140
|
+
round,
|
|
141
|
+
provider: providerKey,
|
|
142
|
+
model: providerConfig.model,
|
|
143
|
+
status: 'skipped',
|
|
144
|
+
error: { message: `API key not set for ${providerKey}` },
|
|
145
|
+
};
|
|
146
|
+
}
|
|
147
|
+
// The debate template (role framing, VERDICT instructions, and, from round
|
|
148
|
+
// 2 on, the transcript) is the system prompt; the user's original request
|
|
149
|
+
// is the user-role message, per the design spec's "Debate system prompts".
|
|
150
|
+
const instructions = priorTurns.length === 0
|
|
151
|
+
? openerPrompt(judgeCount)
|
|
152
|
+
: turnPrompt({
|
|
153
|
+
judgeName: providerKey,
|
|
154
|
+
judgeCount,
|
|
155
|
+
round,
|
|
156
|
+
maxRounds: opts.maxRounds,
|
|
157
|
+
transcript: formatTranscript(priorTurns),
|
|
158
|
+
});
|
|
159
|
+
try {
|
|
160
|
+
const result = await loadProvider(providerKey, providerConfig).chat({
|
|
161
|
+
prompt: opts.prompt,
|
|
162
|
+
system: instructions,
|
|
163
|
+
maxTokens: opts.maxTokens,
|
|
164
|
+
effort: opts.effort,
|
|
165
|
+
model: providerConfig.model,
|
|
166
|
+
});
|
|
167
|
+
return {
|
|
168
|
+
round,
|
|
169
|
+
provider: providerKey,
|
|
170
|
+
model: providerConfig.model,
|
|
171
|
+
status: 'success',
|
|
172
|
+
response: result.content,
|
|
173
|
+
reasoning: result.reasoning,
|
|
174
|
+
usage: result.usage,
|
|
175
|
+
verdict: parseVerdict(result.content),
|
|
176
|
+
};
|
|
177
|
+
}
|
|
178
|
+
catch (err) {
|
|
179
|
+
return {
|
|
180
|
+
round,
|
|
181
|
+
provider: providerKey,
|
|
182
|
+
model: providerConfig.model,
|
|
183
|
+
status: 'error',
|
|
184
|
+
error: { message: err instanceof Error ? err.message : String(err) },
|
|
185
|
+
};
|
|
186
|
+
}
|
|
187
|
+
}
|
|
188
|
+
//# sourceMappingURL=loop.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"loop.js","sourceRoot":"","sources":["../../src/debate/loop.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import type { DebateTurn } from '../types.js';
|
|
2
|
+
export declare function formatTranscript(turns: DebateTurn[]): string;
|
|
3
|
+
export declare function openerPrompt(judgeCount: number): string;
|
|
4
|
+
export declare function turnPrompt(args: {
|
|
5
|
+
judgeName: string;
|
|
6
|
+
judgeCount: number;
|
|
7
|
+
round: number;
|
|
8
|
+
maxRounds: number;
|
|
9
|
+
transcript: string;
|
|
10
|
+
}): string;
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
const MODE_CONTEXT = 'You are a judge on an adversarial review council. Multiple independent ' +
|
|
2
|
+
'models debate the user\'s request until they reach a real consensus.';
|
|
3
|
+
const VERDICT_FOOTER = `End your response with a final line of exactly:
|
|
4
|
+
VERDICT: AGREE
|
|
5
|
+
or
|
|
6
|
+
VERDICT: DISAGREE`;
|
|
7
|
+
export function formatTranscript(turns) {
|
|
8
|
+
return turns
|
|
9
|
+
.filter((t) => t.status === 'success' && t.response)
|
|
10
|
+
.map((t) => `[round ${t.round}] ${t.provider} (${t.model}):\n${t.response}`)
|
|
11
|
+
.join('\n\n');
|
|
12
|
+
}
|
|
13
|
+
export function openerPrompt(judgeCount) {
|
|
14
|
+
return `${MODE_CONTEXT}
|
|
15
|
+
|
|
16
|
+
You are one of ${judgeCount} independent judges debating the user's request.
|
|
17
|
+
Take a clear position and argue it. Do not manufacture objections: if you
|
|
18
|
+
genuinely have no concerns, say so and agree.
|
|
19
|
+
|
|
20
|
+
${VERDICT_FOOTER}
|
|
21
|
+
|
|
22
|
+
AGREE means you endorse the position as it stands and have no remaining
|
|
23
|
+
substantive objection. DISAGREE means you are contesting something specific,
|
|
24
|
+
which your response must state.`;
|
|
25
|
+
}
|
|
26
|
+
export function turnPrompt(args) {
|
|
27
|
+
return `${MODE_CONTEXT}
|
|
28
|
+
|
|
29
|
+
You are ${args.judgeName}, one of ${args.judgeCount} independent judges in round ${args.round} of ${args.maxRounds} of a debate on the user's request. The transcript of the debate so far follows, in speaking order.
|
|
30
|
+
|
|
31
|
+
${args.transcript}
|
|
32
|
+
|
|
33
|
+
Take your turn:
|
|
34
|
+
1. State your current position.
|
|
35
|
+
2. Attack the weakest point in each other judge's most recent turn. Be
|
|
36
|
+
specific; quote what you are contesting. Do not soften disagreement to be
|
|
37
|
+
agreeable, and do not manufacture disagreement for its own sake.
|
|
38
|
+
3. Revise your position if another judge's argument genuinely changed your
|
|
39
|
+
mind, or hold it and say why their attacks fail.
|
|
40
|
+
|
|
41
|
+
${VERDICT_FOOTER}
|
|
42
|
+
|
|
43
|
+
AGREE means you endorse the emerging shared position and have no remaining
|
|
44
|
+
substantive objection. DISAGREE means the transcript does not yet reflect a
|
|
45
|
+
position you can endorse, and your response states what is still wrong.`;
|
|
46
|
+
}
|
|
47
|
+
//# sourceMappingURL=prompts.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"prompts.js","sourceRoot":"","sources":["../../src/debate/prompts.ts"],"names":[],"mappings":"AAEA,MAAM,YAAY,GAChB,yEAAyE;IACzE,sEAAsE,CAAC;AAEzE,MAAM,cAAc,GAAG;;;kBAGL,CAAC;AAEnB,MAAM,UAAU,gBAAgB,CAAC,KAAmB;IAClD,OAAO,KAAK;SACT,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,MAAM,KAAK,SAAS,IAAI,CAAC,CAAC,QAAQ,CAAC;SACnD,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,UAAU,CAAC,CAAC,KAAK,KAAK,CAAC,CAAC,QAAQ,KAAK,CAAC,CAAC,KAAK,OAAO,CAAC,CAAC,QAAQ,EAAE,CAAC;SAC3E,IAAI,CAAC,MAAM,CAAC,CAAC;AAClB,CAAC;AAED,MAAM,UAAU,YAAY,CAAC,UAAkB;IAC7C,OAAO,GAAG,YAAY;;iBAEP,UAAU;;;;EAIzB,cAAc;;;;gCAIgB,CAAC;AACjC,CAAC;AAED,MAAM,UAAU,UAAU,CAAC,IAM1B;IACC,OAAO,GAAG,YAAY;;UAEd,IAAI,CAAC,SAAS,YAAY,IAAI,CAAC,UAAU,gCAAgC,IAAI,CAAC,KAAK,OAAO,IAAI,CAAC,SAAS;;EAEhH,IAAI,CAAC,UAAU;;;;;;;;;;EAUf,cAAc;;;;wEAIwD,CAAC;AACzE,CAAC"}
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import type { DebateOutput, DebateTurn } from '../types.js';
|
|
2
|
+
export declare function buildDebateOutput(args: {
|
|
3
|
+
prompt: string;
|
|
4
|
+
turns: DebateTurn[];
|
|
5
|
+
consensus: boolean;
|
|
6
|
+
maxRounds: number;
|
|
7
|
+
totalCount: number;
|
|
8
|
+
warnings?: string[];
|
|
9
|
+
}): DebateOutput;
|
|
10
|
+
export declare function renderDebateTOON(output: DebateOutput, opts: {
|
|
11
|
+
full: boolean;
|
|
12
|
+
}): string;
|
|
13
|
+
export declare function renderDebatePaused(args: {
|
|
14
|
+
sessionId: string;
|
|
15
|
+
round: number;
|
|
16
|
+
maxRounds: number;
|
|
17
|
+
turnIndex: number;
|
|
18
|
+
turnCount: number;
|
|
19
|
+
unseenTurns: DebateTurn[];
|
|
20
|
+
seenRounds: number;
|
|
21
|
+
seenBytes: number;
|
|
22
|
+
}): string;
|
|
@@ -0,0 +1,112 @@
|
|
|
1
|
+
import { synthesizeDebate } from '../chairman.js';
|
|
2
|
+
import { formatTranscript } from './prompts.js';
|
|
3
|
+
import { CALLER } from './loop.js';
|
|
4
|
+
import { previewPrompt } from '../output.js';
|
|
5
|
+
export function buildDebateOutput(args) {
|
|
6
|
+
const rounds = [];
|
|
7
|
+
for (const turn of args.turns) {
|
|
8
|
+
let bucket = rounds.find((r) => r.round === turn.round);
|
|
9
|
+
if (!bucket) {
|
|
10
|
+
bucket = { round: turn.round, turns: [] };
|
|
11
|
+
rounds.push(bucket);
|
|
12
|
+
}
|
|
13
|
+
bucket.turns.push(turn);
|
|
14
|
+
}
|
|
15
|
+
rounds.sort((a, b) => a.round - b.round);
|
|
16
|
+
const finalByParticipant = new Map();
|
|
17
|
+
for (const turn of args.turns) {
|
|
18
|
+
if (turn.status === 'success')
|
|
19
|
+
finalByParticipant.set(turn.provider, turn);
|
|
20
|
+
}
|
|
21
|
+
const judges = [...finalByParticipant.values()];
|
|
22
|
+
return {
|
|
23
|
+
prompt: args.prompt,
|
|
24
|
+
mode: 'debate',
|
|
25
|
+
rounds,
|
|
26
|
+
consensus: args.consensus,
|
|
27
|
+
totalRounds: rounds.length,
|
|
28
|
+
maxRounds: args.maxRounds,
|
|
29
|
+
judges,
|
|
30
|
+
synthesis: synthesizeDebate({ judges, totalRounds: rounds.length, consensus: args.consensus }),
|
|
31
|
+
availableCount: judges.length,
|
|
32
|
+
totalCount: args.totalCount,
|
|
33
|
+
warnings: args.warnings,
|
|
34
|
+
};
|
|
35
|
+
}
|
|
36
|
+
export function renderDebateTOON(output, opts) {
|
|
37
|
+
const lines = [];
|
|
38
|
+
lines.push(`council[debate]: "${previewPrompt(output.prompt)}"`);
|
|
39
|
+
lines.push(`judges: ${output.availableCount} of ${output.totalCount} responded`);
|
|
40
|
+
lines.push(`rounds[${output.rounds.length}]{round,agree,disagree,active}:`);
|
|
41
|
+
for (const r of output.rounds) {
|
|
42
|
+
const ok = r.turns.filter((t) => t.status === 'success');
|
|
43
|
+
const agree = ok.filter((t) => t.verdict === 'agree').length;
|
|
44
|
+
lines.push(` ${r.round},${agree},${ok.length - agree},${ok.length}`);
|
|
45
|
+
}
|
|
46
|
+
lines.push(output.consensus
|
|
47
|
+
? `consensus: reached in ${output.totalRounds} of ${output.maxRounds} rounds`
|
|
48
|
+
: `consensus: none after ${output.totalRounds} of ${output.maxRounds} rounds`);
|
|
49
|
+
lines.push(`judges[${output.judges.length}]{provider,model,status,verdict}:`);
|
|
50
|
+
for (const j of output.judges) {
|
|
51
|
+
lines.push(` ${j.provider},${j.model},${j.status},${j.verdict ?? 'unavailable'}`);
|
|
52
|
+
}
|
|
53
|
+
const transcript = formatTranscript(output.rounds.flatMap((r) => r.turns));
|
|
54
|
+
if (!opts.full) {
|
|
55
|
+
lines.push(`transcript: ${output.totalRounds} rounds, ${kb(transcript)} - rerun with --full for complete transcript`);
|
|
56
|
+
}
|
|
57
|
+
if (output.warnings && output.warnings.length > 0) {
|
|
58
|
+
lines.push(`warnings[${output.warnings.length}]:`);
|
|
59
|
+
for (const w of output.warnings)
|
|
60
|
+
lines.push(` ${w}`);
|
|
61
|
+
}
|
|
62
|
+
lines.push('synthesis:');
|
|
63
|
+
for (const line of output.synthesis.split('\n'))
|
|
64
|
+
lines.push(` ${line}`);
|
|
65
|
+
if (opts.full) {
|
|
66
|
+
lines.push('transcript:');
|
|
67
|
+
for (const line of transcript.split('\n'))
|
|
68
|
+
lines.push(` ${line}`);
|
|
69
|
+
}
|
|
70
|
+
// Help lines suggest --models values, so the caller (not a provider) must
|
|
71
|
+
// never appear in them.
|
|
72
|
+
const providers = output.judges.filter((j) => j.provider !== CALLER);
|
|
73
|
+
const help = [];
|
|
74
|
+
if (output.consensus) {
|
|
75
|
+
help.push(`Run \`npx -y @lanjak/council debate "<prompt>" --models ${providers.map((j) => j.provider).join(',')}\``);
|
|
76
|
+
}
|
|
77
|
+
else {
|
|
78
|
+
const dissenters = providers.filter((j) => j.verdict !== 'agree').map((j) => j.provider);
|
|
79
|
+
help.push('No consensus - continue with more rounds: rerun with --max-rounds ' + (output.maxRounds + 3));
|
|
80
|
+
if (dissenters.length > 0) {
|
|
81
|
+
help.push(`Or narrow to the dissenters: rerun with --models ${dissenters.join(',')}`);
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
lines.push(`help[${help.length}]:`);
|
|
85
|
+
for (const h of help)
|
|
86
|
+
lines.push(` ${h}`);
|
|
87
|
+
return lines.join('\n');
|
|
88
|
+
}
|
|
89
|
+
export function renderDebatePaused(args) {
|
|
90
|
+
const lines = [];
|
|
91
|
+
lines.push(`council[debate]: awaiting your turn`);
|
|
92
|
+
lines.push(`status: awaiting-caller (round ${args.round} of ${args.maxRounds}, turn ${args.turnIndex} of ${args.turnCount})`);
|
|
93
|
+
lines.push(`session: ${args.sessionId}`);
|
|
94
|
+
if (args.seenRounds > 0) {
|
|
95
|
+
lines.push(`seen: ${args.seenRounds} rounds, ${formatKB(args.seenBytes)} - already shown in your previous turn`);
|
|
96
|
+
}
|
|
97
|
+
lines.push('transcript:');
|
|
98
|
+
for (const line of formatTranscript(args.unseenTurns).split('\n'))
|
|
99
|
+
lines.push(` ${line}`);
|
|
100
|
+
lines.push('help[2]:');
|
|
101
|
+
lines.push(' It is your turn. Read the transcript above, take a position, attack the');
|
|
102
|
+
lines.push(` weakest points of the other judges' latest turns, then respond with:`);
|
|
103
|
+
lines.push(` echo "<your turn, ending with VERDICT: AGREE or VERDICT: DISAGREE>" | npx -y @lanjak/council debate turn ${args.sessionId} --stdin`);
|
|
104
|
+
return lines.join('\n');
|
|
105
|
+
}
|
|
106
|
+
function kb(text) {
|
|
107
|
+
return formatKB(Buffer.byteLength(text, 'utf8'));
|
|
108
|
+
}
|
|
109
|
+
function formatKB(bytes) {
|
|
110
|
+
return `${(bytes / 1024).toFixed(1)}KB`;
|
|
111
|
+
}
|
|
112
|
+
//# sourceMappingURL=render.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"render.js","sourceRoot":"","sources":["../../src/debate/render.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
import type { DebateSession } from '../types.js';
|
|
2
|
+
export declare function newSessionId(): string;
|
|
3
|
+
export declare function sessionPath(id: string, env?: NodeJS.ProcessEnv, project?: string): string;
|
|
4
|
+
export declare function saveSession(session: DebateSession, env?: NodeJS.ProcessEnv): void;
|
|
5
|
+
export declare function loadSession(id: string, env?: NodeJS.ProcessEnv): DebateSession;
|
|
6
|
+
export declare function deleteSession(id: string, env?: NodeJS.ProcessEnv): void;
|
|
7
|
+
export declare function cleanupExpired(env?: NodeJS.ProcessEnv): void;
|
|
@@ -0,0 +1,85 @@
|
|
|
1
|
+
import * as crypto from 'node:crypto';
|
|
2
|
+
import * as fs from 'node:fs';
|
|
3
|
+
import * as os from 'node:os';
|
|
4
|
+
import * as path from 'node:path';
|
|
5
|
+
import { CouncilError } from '../errors.js';
|
|
6
|
+
const TTL_MS = 24 * 60 * 60 * 1000;
|
|
7
|
+
export function newSessionId() {
|
|
8
|
+
return `dbt-${crypto.randomBytes(3).toString('hex')}`;
|
|
9
|
+
}
|
|
10
|
+
export function sessionPath(id, env = process.env, project = 'council') {
|
|
11
|
+
const base = env.XDG_STATE_HOME && env.XDG_STATE_HOME.length > 0
|
|
12
|
+
? env.XDG_STATE_HOME
|
|
13
|
+
: path.join(os.homedir(), '.local', 'state');
|
|
14
|
+
return path.join(base, project, 'debates', `${id.replace(/[^a-zA-Z0-9._-]/g, '_')}.json`);
|
|
15
|
+
}
|
|
16
|
+
export function saveSession(session, env = process.env) {
|
|
17
|
+
const target = sessionPath(session.id, env);
|
|
18
|
+
fs.mkdirSync(path.dirname(target), { recursive: true });
|
|
19
|
+
const fd = fs.openSync(target, 'w');
|
|
20
|
+
try {
|
|
21
|
+
fs.writeSync(fd, JSON.stringify(session));
|
|
22
|
+
fs.fsyncSync(fd); // durable before exit: the caller may resume from another process immediately
|
|
23
|
+
}
|
|
24
|
+
finally {
|
|
25
|
+
fs.closeSync(fd);
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
export function loadSession(id, env = process.env) {
|
|
29
|
+
const current = sessionPath(id, env);
|
|
30
|
+
const target = fs.existsSync(current) ? current : sessionPath(id, env, 'council-axi');
|
|
31
|
+
const notFound = new CouncilError(`Debate session "${id}" not found or expired. Start a new one with: council debate "<prompt>" --participate`, 'SESSION_NOT_FOUND');
|
|
32
|
+
let raw;
|
|
33
|
+
try {
|
|
34
|
+
raw = fs.readFileSync(target, 'utf8');
|
|
35
|
+
}
|
|
36
|
+
catch {
|
|
37
|
+
throw notFound;
|
|
38
|
+
}
|
|
39
|
+
let session;
|
|
40
|
+
try {
|
|
41
|
+
session = JSON.parse(raw);
|
|
42
|
+
}
|
|
43
|
+
catch {
|
|
44
|
+
fs.rmSync(target, { force: true });
|
|
45
|
+
throw notFound;
|
|
46
|
+
}
|
|
47
|
+
const age = Date.now() - Date.parse(session.createdAt);
|
|
48
|
+
if (!Number.isFinite(age) || age > TTL_MS) {
|
|
49
|
+
fs.rmSync(target, { force: true });
|
|
50
|
+
throw notFound;
|
|
51
|
+
}
|
|
52
|
+
return session;
|
|
53
|
+
}
|
|
54
|
+
export function deleteSession(id, env = process.env) {
|
|
55
|
+
fs.rmSync(sessionPath(id, env), { force: true });
|
|
56
|
+
fs.rmSync(sessionPath(id, env, 'council-axi'), { force: true });
|
|
57
|
+
}
|
|
58
|
+
export function cleanupExpired(env = process.env) {
|
|
59
|
+
for (const project of ['council', 'council-axi']) {
|
|
60
|
+
cleanupDirectory(path.dirname(sessionPath('x', env, project)));
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
function cleanupDirectory(dir) {
|
|
64
|
+
let entries;
|
|
65
|
+
try {
|
|
66
|
+
entries = fs.readdirSync(dir);
|
|
67
|
+
}
|
|
68
|
+
catch {
|
|
69
|
+
return;
|
|
70
|
+
}
|
|
71
|
+
for (const name of entries) {
|
|
72
|
+
try {
|
|
73
|
+
const raw = fs.readFileSync(path.join(dir, name), 'utf8');
|
|
74
|
+
const session = JSON.parse(raw);
|
|
75
|
+
const age = Date.now() - Date.parse(session.createdAt);
|
|
76
|
+
if (!Number.isFinite(age) || age > TTL_MS) {
|
|
77
|
+
fs.rmSync(path.join(dir, name), { force: true });
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
catch {
|
|
81
|
+
// best effort - never let cleanup break a command
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
//# sourceMappingURL=session.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"session.js","sourceRoot":"","sources":["../../src/debate/session.ts"],"names":[],"mappings":"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"}
|