@cat-factory/consensus 0.6.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.
Files changed (38) hide show
  1. package/LICENSE +21 -0
  2. package/dist/ConsensusAgentExecutor.d.ts +68 -0
  3. package/dist/ConsensusAgentExecutor.d.ts.map +1 -0
  4. package/dist/ConsensusAgentExecutor.js +237 -0
  5. package/dist/ConsensusAgentExecutor.js.map +1 -0
  6. package/dist/gating.d.ts +15 -0
  7. package/dist/gating.d.ts.map +1 -0
  8. package/dist/gating.js +28 -0
  9. package/dist/gating.js.map +1 -0
  10. package/dist/index.d.ts +9 -0
  11. package/dist/index.d.ts.map +1 -0
  12. package/dist/index.js +11 -0
  13. package/dist/index.js.map +1 -0
  14. package/dist/strategies/debate.d.ts +9 -0
  15. package/dist/strategies/debate.d.ts.map +1 -0
  16. package/dist/strategies/debate.js +75 -0
  17. package/dist/strategies/debate.js.map +1 -0
  18. package/dist/strategies/rankedVoting.d.ts +12 -0
  19. package/dist/strategies/rankedVoting.d.ts.map +1 -0
  20. package/dist/strategies/rankedVoting.js +108 -0
  21. package/dist/strategies/rankedVoting.js.map +1 -0
  22. package/dist/strategies/shared.d.ts +25 -0
  23. package/dist/strategies/shared.d.ts.map +1 -0
  24. package/dist/strategies/shared.js +81 -0
  25. package/dist/strategies/shared.js.map +1 -0
  26. package/dist/strategies/specialistPanel.d.ts +9 -0
  27. package/dist/strategies/specialistPanel.d.ts.map +1 -0
  28. package/dist/strategies/specialistPanel.js +42 -0
  29. package/dist/strategies/specialistPanel.js.map +1 -0
  30. package/dist/strategies/types.d.ts +71 -0
  31. package/dist/strategies/types.d.ts.map +1 -0
  32. package/dist/strategies/types.js +2 -0
  33. package/dist/strategies/types.js.map +1 -0
  34. package/dist/traits.d.ts +35 -0
  35. package/dist/traits.d.ts.map +1 -0
  36. package/dist/traits.js +64 -0
  37. package/dist/traits.js.map +1 -0
  38. package/package.json +37 -0
package/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Igor Savin
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.
@@ -0,0 +1,68 @@
1
+ import { type AgentExecutor, type AgentJobHandle, type AgentJobUpdate, type AgentRunContext, type AgentRunResult, type AsyncAgentExecutor, type ConsensusSessionRepository, type ExecutionEventPublisher, type ModelProvider, type ModelProviderResolver, type ModelRef } from '@cat-factory/kernel';
2
+ import { type AgentRouting } from '@cat-factory/agents';
3
+ import type { GenerateFn } from './strategies/types.js';
4
+ export interface ConsensusAgentExecutorDependencies {
5
+ /**
6
+ * The standard executor (typically the `CompositeAgentExecutor`) consensus wraps and
7
+ * DELEGATES to: when a step is not consensus-enabled, or gating marks the task
8
+ * ineligible, the standard single-actor agent runs exactly as before (preserving the
9
+ * container/async path for kinds that need a checkout).
10
+ */
11
+ standard: AgentExecutor;
12
+ /** Per-scope model provider (preferred); leases the run's DB-backed API keys. */
13
+ modelProviderResolver?: ModelProviderResolver;
14
+ /** Static provider (tests / no pool). One of the two MUST be present. */
15
+ modelProvider?: ModelProvider;
16
+ agentRouting: AgentRouting;
17
+ resolveBlockModel?: (modelId: string | undefined) => ModelRef | undefined;
18
+ resolveWorkspaceModelDefault?: (workspaceId: string, agentKind: string) => Promise<string | undefined>;
19
+ /** Persists the session transcript (the observability surface). Optional. */
20
+ sessionRepository?: ConsensusSessionRepository;
21
+ /** Pushes live transcript updates to the SPA. Optional. */
22
+ eventPublisher?: ExecutionEventPublisher;
23
+ /** Epoch-ms clock; defaults to Date.now. */
24
+ now?: () => number;
25
+ /** Structured logger; optional. */
26
+ logger?: {
27
+ info(obj: unknown, msg?: string): void;
28
+ warn?(obj: unknown, msg?: string): void;
29
+ };
30
+ /** Inject the LLM call (tests); defaults to the Vercel AI SDK wrapper. */
31
+ generate?: GenerateFn;
32
+ }
33
+ /**
34
+ * An {@link AgentExecutor} that runs an eligible, consensus-enabled step through a
35
+ * multi-model consensus process (specialist panel / debate / ranked voting), persisting
36
+ * the transcript and returning a normal {@link AgentRunResult} of the SAME shape the
37
+ * underlying agent kind would have produced — so the rest of the engine is untouched.
38
+ * Every other step delegates to the wrapped standard executor.
39
+ */
40
+ export declare class ConsensusAgentExecutor implements AsyncAgentExecutor {
41
+ private readonly deps;
42
+ private readonly resolveBlockModel;
43
+ private readonly now;
44
+ private readonly generate;
45
+ constructor(deps: ConsensusAgentExecutorDependencies);
46
+ /**
47
+ * Whether this step should actually run consensus (enabled, the kind carries a
48
+ * consensus capability trait, ≥2 participants, gate passes). The eligibility check
49
+ * is the runtime backstop for the builder's UI guard: a pipeline crafted via the
50
+ * API with a consensus config on an INELIGIBLE kind (e.g. the container `coder`,
51
+ * which must clone/edit/commit/PR) must NOT be diverted to an inline multi-model
52
+ * panel — it falls through to the standard executor unchanged.
53
+ */
54
+ private consensusActive;
55
+ private providerFor;
56
+ private baseRef;
57
+ /** A participant/synthesizer's ref: its pinned model (degraded for inline) else the base ref. */
58
+ private refForModelId;
59
+ run(context: AgentRunContext): Promise<AgentRunResult>;
60
+ private emit;
61
+ resolveModel(context: AgentRunContext): Promise<string | undefined>;
62
+ isQuotaBased(context: AgentRunContext): Promise<boolean>;
63
+ runsAsync(context: AgentRunContext): boolean;
64
+ startJob(context: AgentRunContext): Promise<AgentJobHandle>;
65
+ pollJob(handle: AgentJobHandle): Promise<AgentJobUpdate>;
66
+ stopJob(handle: AgentJobHandle): Promise<void>;
67
+ }
68
+ //# sourceMappingURL=ConsensusAgentExecutor.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ConsensusAgentExecutor.d.ts","sourceRoot":"","sources":["../src/ConsensusAgentExecutor.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,KAAK,aAAa,EAClB,KAAK,cAAc,EACnB,KAAK,cAAc,EACnB,KAAK,eAAe,EACpB,KAAK,cAAc,EACnB,KAAK,kBAAkB,EAGvB,KAAK,0BAA0B,EAC/B,KAAK,uBAAuB,EAC5B,KAAK,aAAa,EAClB,KAAK,qBAAqB,EAC1B,KAAK,QAAQ,EAGd,MAAM,qBAAqB,CAAA;AAC5B,OAAO,EACL,KAAK,YAAY,EAMlB,MAAM,qBAAqB,CAAA;AAO5B,OAAO,KAAK,EACV,UAAU,EAIX,MAAM,uBAAuB,CAAA;AAE9B,MAAM,WAAW,kCAAkC;IACjD;;;;;OAKG;IACH,QAAQ,EAAE,aAAa,CAAA;IACvB,iFAAiF;IACjF,qBAAqB,CAAC,EAAE,qBAAqB,CAAA;IAC7C,yEAAyE;IACzE,aAAa,CAAC,EAAE,aAAa,CAAA;IAC7B,YAAY,EAAE,YAAY,CAAA;IAC1B,iBAAiB,CAAC,EAAE,CAAC,OAAO,EAAE,MAAM,GAAG,SAAS,KAAK,QAAQ,GAAG,SAAS,CAAA;IACzE,4BAA4B,CAAC,EAAE,CAC7B,WAAW,EAAE,MAAM,EACnB,SAAS,EAAE,MAAM,KACd,OAAO,CAAC,MAAM,GAAG,SAAS,CAAC,CAAA;IAChC,6EAA6E;IAC7E,iBAAiB,CAAC,EAAE,0BAA0B,CAAA;IAC9C,2DAA2D;IAC3D,cAAc,CAAC,EAAE,uBAAuB,CAAA;IACxC,4CAA4C;IAC5C,GAAG,CAAC,EAAE,MAAM,MAAM,CAAA;IAClB,mCAAmC;IACnC,MAAM,CAAC,EAAE;QAAE,IAAI,CAAC,GAAG,EAAE,OAAO,EAAE,GAAG,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;QAAC,IAAI,CAAC,CAAC,GAAG,EAAE,OAAO,EAAE,GAAG,CAAC,EAAE,MAAM,GAAG,IAAI,CAAA;KAAE,CAAA;IAC5F,0EAA0E;IAC1E,QAAQ,CAAC,EAAE,UAAU,CAAA;CACtB;AAQD;;;;;;GAMG;AACH,qBAAa,sBAAuB,YAAW,kBAAkB;IAC/D,OAAO,CAAC,QAAQ,CAAC,IAAI,CAAoC;IACzD,OAAO,CAAC,QAAQ,CAAC,iBAAiB,CAAuD;IACzF,OAAO,CAAC,QAAQ,CAAC,GAAG,CAAc;IAClC,OAAO,CAAC,QAAQ,CAAC,QAAQ,CAAY;IAErC,YAAY,IAAI,EAAE,kCAAkC,EAQnD;IAED;;;;;;;OAOG;IACH,OAAO,CAAC,eAAe;YAQT,WAAW;IAczB,OAAO,CAAC,OAAO;IAef,iGAAiG;IACjG,OAAO,CAAC,aAAa;IAQf,GAAG,CAAC,OAAO,EAAE,eAAe,GAAG,OAAO,CAAC,cAAc,CAAC,CA4G3D;YAEa,IAAI;IAcZ,YAAY,CAAC,OAAO,EAAE,eAAe,GAAG,OAAO,CAAC,MAAM,GAAG,SAAS,CAAC,CAOxE;IAED,YAAY,CAAC,OAAO,EAAE,eAAe,GAAG,OAAO,CAAC,OAAO,CAAC,CAIvD;IAKD,SAAS,CAAC,OAAO,EAAE,eAAe,GAAG,OAAO,CAG3C;IAED,QAAQ,CAAC,OAAO,EAAE,eAAe,GAAG,OAAO,CAAC,cAAc,CAAC,CAK1D;IAED,OAAO,CAAC,MAAM,EAAE,cAAc,GAAG,OAAO,CAAC,cAAc,CAAC,CAKvD;IAEK,OAAO,CAAC,MAAM,EAAE,cAAc,GAAG,OAAO,CAAC,IAAI,CAAC,CAInD;CACF"}
@@ -0,0 +1,237 @@
1
+ import { inlineModelRef, isAsyncAgentExecutor, } from '@cat-factory/kernel';
2
+ import { composeBlockSystemPrompt, resolveAgentConfig, resolveInlineModelRef, systemPromptFor, userPromptFor, } from '@cat-factory/agents';
3
+ import { decideConsensusMode } from './gating.js';
4
+ import { isConsensusEligible } from './traits.js';
5
+ import { runSpecialistPanel } from './strategies/specialistPanel.js';
6
+ import { runDebate } from './strategies/debate.js';
7
+ import { runRankedVoting } from './strategies/rankedVoting.js';
8
+ import { defaultGenerate } from './strategies/shared.js';
9
+ const STRATEGIES = {
10
+ 'specialist-panel': runSpecialistPanel,
11
+ debate: runDebate,
12
+ 'ranked-voting': runRankedVoting,
13
+ };
14
+ /**
15
+ * An {@link AgentExecutor} that runs an eligible, consensus-enabled step through a
16
+ * multi-model consensus process (specialist panel / debate / ranked voting), persisting
17
+ * the transcript and returning a normal {@link AgentRunResult} of the SAME shape the
18
+ * underlying agent kind would have produced — so the rest of the engine is untouched.
19
+ * Every other step delegates to the wrapped standard executor.
20
+ */
21
+ export class ConsensusAgentExecutor {
22
+ deps;
23
+ resolveBlockModel;
24
+ now;
25
+ generate;
26
+ constructor(deps) {
27
+ if (!deps.modelProviderResolver && !deps.modelProvider) {
28
+ throw new Error('ConsensusAgentExecutor requires a modelProviderResolver or a modelProvider');
29
+ }
30
+ this.deps = deps;
31
+ this.resolveBlockModel = deps.resolveBlockModel ?? (() => undefined);
32
+ this.now = deps.now ?? (() => Date.now());
33
+ this.generate = deps.generate ?? defaultGenerate;
34
+ }
35
+ /**
36
+ * Whether this step should actually run consensus (enabled, the kind carries a
37
+ * consensus capability trait, ≥2 participants, gate passes). The eligibility check
38
+ * is the runtime backstop for the builder's UI guard: a pipeline crafted via the
39
+ * API with a consensus config on an INELIGIBLE kind (e.g. the container `coder`,
40
+ * which must clone/edit/commit/PR) must NOT be diverted to an inline multi-model
41
+ * panel — it falls through to the standard executor unchanged.
42
+ */
43
+ consensusActive(context) {
44
+ const cfg = context.consensus;
45
+ if (!cfg || !cfg.enabled)
46
+ return false;
47
+ if (!isConsensusEligible(context.agentKind))
48
+ return false;
49
+ if (cfg.participants.length < 2)
50
+ return false;
51
+ return decideConsensusMode(context.block.estimate, cfg.gating) === 'consensus';
52
+ }
53
+ async providerFor(context) {
54
+ if (this.deps.modelProviderResolver && context.workspaceId) {
55
+ return this.deps.modelProviderResolver.forScope({
56
+ workspaceId: context.workspaceId,
57
+ userId: context.initiatedByUserId,
58
+ });
59
+ }
60
+ if (this.deps.modelProvider)
61
+ return this.deps.modelProvider;
62
+ if (this.deps.modelProviderResolver) {
63
+ return this.deps.modelProviderResolver.forScope({ workspaceId: context.workspaceId ?? '' });
64
+ }
65
+ throw new Error('ConsensusAgentExecutor: no model provider available');
66
+ }
67
+ baseRef(context) {
68
+ return resolveInlineModelRef({
69
+ agentRouting: this.deps.agentRouting,
70
+ resolveBlockModel: this.resolveBlockModel,
71
+ resolveWorkspaceModelDefault: this.deps.resolveWorkspaceModelDefault,
72
+ }, {
73
+ agentKind: context.agentKind,
74
+ blockModelId: context.block.modelId,
75
+ workspaceId: context.workspaceId,
76
+ });
77
+ }
78
+ /** A participant/synthesizer's ref: its pinned model (degraded for inline) else the base ref. */
79
+ refForModelId(modelId, base) {
80
+ if (modelId) {
81
+ const pinned = this.resolveBlockModel(modelId);
82
+ if (pinned)
83
+ return inlineModelRef(pinned, base);
84
+ }
85
+ return base;
86
+ }
87
+ async run(context) {
88
+ if (!this.consensusActive(context))
89
+ return this.deps.standard.run(context);
90
+ const cfg = context.consensus;
91
+ const provider = await this.providerFor(context);
92
+ const base = await this.baseRef(context);
93
+ const config = resolveAgentConfig(this.deps.agentRouting, context.agentKind);
94
+ const baseSystem = composeBlockSystemPrompt(config.system ?? systemPromptFor(context.agentKind), context.block);
95
+ const goalPrompt = userPromptFor(context);
96
+ const participants = cfg.participants.map((p) => {
97
+ const ref = this.refForModelId(p.modelId, base);
98
+ return {
99
+ id: p.id,
100
+ role: p.role,
101
+ ...(p.systemFraming ? { systemFraming: p.systemFraming } : {}),
102
+ model: provider.resolve(ref),
103
+ modelLabel: `${ref.provider}:${ref.model}`,
104
+ };
105
+ });
106
+ const synthRef = this.refForModelId(cfg.synthesizerModelId, base);
107
+ const synthesizer = {
108
+ model: provider.resolve(synthRef),
109
+ modelLabel: `${synthRef.provider}:${synthRef.model}`,
110
+ };
111
+ const session = {
112
+ id: `cns_${context.executionId ?? 'x'}_${context.stepIndex}`,
113
+ blockId: context.block.id ?? '',
114
+ executionId: context.executionId ?? null,
115
+ stepIndex: context.stepIndex,
116
+ agentKind: context.agentKind,
117
+ strategy: cfg.strategy,
118
+ status: 'running',
119
+ participants: cfg.participants,
120
+ rounds: [],
121
+ synthesis: null,
122
+ confidence: null,
123
+ dissent: [],
124
+ error: null,
125
+ createdAt: this.now(),
126
+ updatedAt: this.now(),
127
+ };
128
+ await this.emit(context, session);
129
+ this.deps.logger?.info({
130
+ msg: 'consensus.start',
131
+ strategy: cfg.strategy,
132
+ agentKind: context.agentKind,
133
+ participants: participants.length,
134
+ executionId: context.executionId,
135
+ stepIndex: context.stepIndex,
136
+ }, 'consensus session started');
137
+ const tags = {
138
+ agentKind: context.agentKind,
139
+ workspaceId: context.workspaceId,
140
+ executionId: context.executionId,
141
+ };
142
+ try {
143
+ const result = await STRATEGIES[cfg.strategy]({
144
+ agentKind: context.agentKind,
145
+ baseSystem,
146
+ goalPrompt,
147
+ participants,
148
+ synthesizer,
149
+ rounds: cfg.rounds ?? 2,
150
+ generate: this.generate,
151
+ tags,
152
+ onProgress: async (update) => {
153
+ session.rounds = update.rounds;
154
+ session.status = update.status;
155
+ session.updatedAt = this.now();
156
+ await this.emit(context, session);
157
+ },
158
+ });
159
+ session.rounds = result.rounds;
160
+ session.synthesis = result.synthesis;
161
+ session.confidence = result.confidence;
162
+ session.dissent = result.dissent;
163
+ session.status = 'done';
164
+ session.updatedAt = this.now();
165
+ await this.emit(context, session);
166
+ this.deps.logger?.info({ msg: 'consensus.done', strategy: cfg.strategy, confidence: result.confidence }, 'consensus session complete');
167
+ return {
168
+ output: result.synthesis,
169
+ model: `consensus:${cfg.strategy}:${synthesizer.modelLabel}`,
170
+ usage: result.usage,
171
+ };
172
+ }
173
+ catch (error) {
174
+ session.status = 'failed';
175
+ session.error = error instanceof Error ? error.message : String(error);
176
+ session.updatedAt = this.now();
177
+ await this.emit(context, session);
178
+ this.deps.logger?.warn?.({ msg: 'consensus.failed', error: session.error }, 'consensus session failed');
179
+ throw error;
180
+ }
181
+ }
182
+ async emit(context, session) {
183
+ if (!context.workspaceId)
184
+ return;
185
+ try {
186
+ await this.deps.sessionRepository?.upsert(context.workspaceId, session);
187
+ }
188
+ catch {
189
+ // Persistence is best-effort observability; never wedge the run.
190
+ }
191
+ try {
192
+ await this.deps.eventPublisher?.consensusSessionChanged?.(context.workspaceId, session);
193
+ }
194
+ catch {
195
+ // Push is best-effort.
196
+ }
197
+ }
198
+ async resolveModel(context) {
199
+ if (!this.consensusActive(context)) {
200
+ return this.deps.standard.resolveModel?.(context) ?? Promise.resolve(undefined);
201
+ }
202
+ const base = await this.baseRef(context);
203
+ const ref = this.refForModelId(context.consensus.synthesizerModelId, base);
204
+ return `consensus:${context.consensus.strategy}:${ref.provider}:${ref.model}`;
205
+ }
206
+ isQuotaBased(context) {
207
+ // Consensus makes metered inline calls; only the delegated path can be quota-based.
208
+ if (this.consensusActive(context))
209
+ return Promise.resolve(false);
210
+ return this.deps.standard.isQuotaBased?.(context) ?? Promise.resolve(false);
211
+ }
212
+ // --- Async delegation: only ever reached for non-consensus (delegated) steps, since
213
+ // `runsAsync` returns false while consensus is active (forcing the engine's inline path).
214
+ runsAsync(context) {
215
+ if (this.consensusActive(context))
216
+ return false;
217
+ return isAsyncAgentExecutor(this.deps.standard) && this.deps.standard.runsAsync(context);
218
+ }
219
+ startJob(context) {
220
+ if (!isAsyncAgentExecutor(this.deps.standard)) {
221
+ throw new Error(`No async executor for agent kind '${context.agentKind}'`);
222
+ }
223
+ return this.deps.standard.startJob(context);
224
+ }
225
+ pollJob(handle) {
226
+ if (!isAsyncAgentExecutor(this.deps.standard)) {
227
+ throw new Error('Wrapped executor does not support async jobs');
228
+ }
229
+ return this.deps.standard.pollJob(handle);
230
+ }
231
+ async stopJob(handle) {
232
+ if (isAsyncAgentExecutor(this.deps.standard) && this.deps.standard.stopJob) {
233
+ await this.deps.standard.stopJob(handle);
234
+ }
235
+ }
236
+ }
237
+ //# sourceMappingURL=ConsensusAgentExecutor.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ConsensusAgentExecutor.js","sourceRoot":"","sources":["../src/ConsensusAgentExecutor.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,15 @@
1
+ import type { ConsensusGating, TaskEstimate } from '@cat-factory/kernel';
2
+ export type ConsensusMode = 'consensus' | 'standard';
3
+ /**
4
+ * Decide whether to run consensus given the task estimate and the step's gating config.
5
+ *
6
+ * - No gating / gating disabled → always `consensus` (the user opted in unconditionally).
7
+ * - Gating enabled, estimate present → `consensus` iff ANY supplied axis is met or
8
+ * exceeded (risk ≥ minRisk OR impact ≥ minImpact OR complexity ≥ minComplexity).
9
+ * A gating block with no thresholds set never triggers on score (so it falls to
10
+ * `standard`) — configuring gating means you must give it at least one bar.
11
+ * - Gating enabled, estimate absent → `gating.onMissingEstimate` (default `consensus`,
12
+ * fail-safe to thoroughness: we couldn't prove the task is low-stakes).
13
+ */
14
+ export declare function decideConsensusMode(estimate: TaskEstimate | null | undefined, gating: ConsensusGating | undefined): ConsensusMode;
15
+ //# sourceMappingURL=gating.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"gating.d.ts","sourceRoot":"","sources":["../src/gating.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,eAAe,EAAE,YAAY,EAAE,MAAM,qBAAqB,CAAA;AAMxE,MAAM,MAAM,aAAa,GAAG,WAAW,GAAG,UAAU,CAAA;AAEpD;;;;;;;;;;GAUG;AACH,wBAAgB,mBAAmB,CACjC,QAAQ,EAAE,YAAY,GAAG,IAAI,GAAG,SAAS,EACzC,MAAM,EAAE,eAAe,GAAG,SAAS,GAClC,aAAa,CAaf"}
package/dist/gating.js ADDED
@@ -0,0 +1,28 @@
1
+ /**
2
+ * Decide whether to run consensus given the task estimate and the step's gating config.
3
+ *
4
+ * - No gating / gating disabled → always `consensus` (the user opted in unconditionally).
5
+ * - Gating enabled, estimate present → `consensus` iff ANY supplied axis is met or
6
+ * exceeded (risk ≥ minRisk OR impact ≥ minImpact OR complexity ≥ minComplexity).
7
+ * A gating block with no thresholds set never triggers on score (so it falls to
8
+ * `standard`) — configuring gating means you must give it at least one bar.
9
+ * - Gating enabled, estimate absent → `gating.onMissingEstimate` (default `consensus`,
10
+ * fail-safe to thoroughness: we couldn't prove the task is low-stakes).
11
+ */
12
+ export function decideConsensusMode(estimate, gating) {
13
+ if (!gating || !gating.enabled)
14
+ return 'consensus';
15
+ if (!estimate)
16
+ return gating.onMissingEstimate ?? 'consensus';
17
+ const axes = [
18
+ [gating.minComplexity, estimate.complexity],
19
+ [gating.minRisk, estimate.risk],
20
+ [gating.minImpact, estimate.impact],
21
+ ];
22
+ for (const [threshold, value] of axes) {
23
+ if (threshold !== undefined && value >= threshold)
24
+ return 'consensus';
25
+ }
26
+ return 'standard';
27
+ }
28
+ //# sourceMappingURL=gating.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"gating.js","sourceRoot":"","sources":["../src/gating.ts"],"names":[],"mappings":"AAQA;;;;;;;;;;GAUG;AACH,MAAM,UAAU,mBAAmB,CACjC,QAAyC,EACzC,MAAmC;IAEnC,IAAI,CAAC,MAAM,IAAI,CAAC,MAAM,CAAC,OAAO;QAAE,OAAO,WAAW,CAAA;IAClD,IAAI,CAAC,QAAQ;QAAE,OAAO,MAAM,CAAC,iBAAiB,IAAI,WAAW,CAAA;IAE7D,MAAM,IAAI,GAAwC;QAChD,CAAC,MAAM,CAAC,aAAa,EAAE,QAAQ,CAAC,UAAU,CAAC;QAC3C,CAAC,MAAM,CAAC,OAAO,EAAE,QAAQ,CAAC,IAAI,CAAC;QAC/B,CAAC,MAAM,CAAC,SAAS,EAAE,QAAQ,CAAC,MAAM,CAAC;KACpC,CAAA;IACD,KAAK,MAAM,CAAC,SAAS,EAAE,KAAK,CAAC,IAAI,IAAI,EAAE,CAAC;QACtC,IAAI,SAAS,KAAK,SAAS,IAAI,KAAK,IAAI,SAAS;YAAE,OAAO,WAAW,CAAA;IACvE,CAAC;IACD,OAAO,UAAU,CAAA;AACnB,CAAC"}
@@ -0,0 +1,9 @@
1
+ export { ConsensusAgentExecutor, type ConsensusAgentExecutorDependencies, } from './ConsensusAgentExecutor.js';
2
+ export { decideConsensusMode, type ConsensusMode } from './gating.js';
3
+ export { SPECIALIST_PANEL_CAPABLE, DEBATE_CAPABLE, RANKED_VOTING_CAPABLE, CONSENSUS_TRAITS, STRATEGY_TRAIT, DEFAULT_CONSENSUS_ELIGIBLE_KINDS, registerConsensusTraits, consensusStrategiesFor, isConsensusEligible, } from './traits.js';
4
+ export { runSpecialistPanel } from './strategies/specialistPanel.js';
5
+ export { runDebate } from './strategies/debate.js';
6
+ export { runRankedVoting, parseScoreMap } from './strategies/rankedVoting.js';
7
+ export { defaultGenerate } from './strategies/shared.js';
8
+ export type { ConsensusUsage, GenerateArgs, GenerateFn, GenerateResult, ObsTags, ResolvedParticipant, StrategyInput, StrategyResult, } from './strategies/types.js';
9
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAIA,OAAO,EACL,sBAAsB,EACtB,KAAK,kCAAkC,GACxC,MAAM,6BAA6B,CAAA;AACpC,OAAO,EAAE,mBAAmB,EAAE,KAAK,aAAa,EAAE,MAAM,aAAa,CAAA;AACrE,OAAO,EACL,wBAAwB,EACxB,cAAc,EACd,qBAAqB,EACrB,gBAAgB,EAChB,cAAc,EACd,gCAAgC,EAChC,uBAAuB,EACvB,sBAAsB,EACtB,mBAAmB,GACpB,MAAM,aAAa,CAAA;AACpB,OAAO,EAAE,kBAAkB,EAAE,MAAM,iCAAiC,CAAA;AACpE,OAAO,EAAE,SAAS,EAAE,MAAM,wBAAwB,CAAA;AAClD,OAAO,EAAE,eAAe,EAAE,aAAa,EAAE,MAAM,8BAA8B,CAAA;AAC7E,OAAO,EAAE,eAAe,EAAE,MAAM,wBAAwB,CAAA;AACxD,YAAY,EACV,cAAc,EACd,YAAY,EACZ,UAAU,EACV,cAAc,EACd,OAAO,EACP,mBAAmB,EACnB,aAAa,EACb,cAAc,GACf,MAAM,uBAAuB,CAAA"}
package/dist/index.js ADDED
@@ -0,0 +1,11 @@
1
+ // @cat-factory/consensus — the optional consensus-orchestration mechanism. A deployment
2
+ // mixes it in as a dependency and wires `ConsensusAgentExecutor` (wrapping the standard
3
+ // composite) into each runtime facade; without it the product runs exactly as before.
4
+ export { ConsensusAgentExecutor, } from './ConsensusAgentExecutor.js';
5
+ export { decideConsensusMode } from './gating.js';
6
+ export { SPECIALIST_PANEL_CAPABLE, DEBATE_CAPABLE, RANKED_VOTING_CAPABLE, CONSENSUS_TRAITS, STRATEGY_TRAIT, DEFAULT_CONSENSUS_ELIGIBLE_KINDS, registerConsensusTraits, consensusStrategiesFor, isConsensusEligible, } from './traits.js';
7
+ export { runSpecialistPanel } from './strategies/specialistPanel.js';
8
+ export { runDebate } from './strategies/debate.js';
9
+ export { runRankedVoting, parseScoreMap } from './strategies/rankedVoting.js';
10
+ export { defaultGenerate } from './strategies/shared.js';
11
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,wFAAwF;AACxF,wFAAwF;AACxF,sFAAsF;AAEtF,OAAO,EACL,sBAAsB,GAEvB,MAAM,6BAA6B,CAAA;AACpC,OAAO,EAAE,mBAAmB,EAAsB,MAAM,aAAa,CAAA;AACrE,OAAO,EACL,wBAAwB,EACxB,cAAc,EACd,qBAAqB,EACrB,gBAAgB,EAChB,cAAc,EACd,gCAAgC,EAChC,uBAAuB,EACvB,sBAAsB,EACtB,mBAAmB,GACpB,MAAM,aAAa,CAAA;AACpB,OAAO,EAAE,kBAAkB,EAAE,MAAM,iCAAiC,CAAA;AACpE,OAAO,EAAE,SAAS,EAAE,MAAM,wBAAwB,CAAA;AAClD,OAAO,EAAE,eAAe,EAAE,aAAa,EAAE,MAAM,8BAA8B,CAAA;AAC7E,OAAO,EAAE,eAAe,EAAE,MAAM,wBAAwB,CAAA"}
@@ -0,0 +1,9 @@
1
+ import type { StrategyInput, StrategyResult } from './types.js';
2
+ /**
3
+ * Debate: an initial independent draft round, then `rounds-1` critique rounds in which
4
+ * each participant sees the ANONYMIZED latest peer arguments and revises its own position
5
+ * (defending or conceding on the merits), and finally a neutral judge synthesizes the last
6
+ * round. Independence first, anonymized exposure, explicit disagreement, capped rounds.
7
+ */
8
+ export declare function runDebate(input: StrategyInput): Promise<StrategyResult>;
9
+ //# sourceMappingURL=debate.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"debate.d.ts","sourceRoot":"","sources":["../../src/strategies/debate.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAuC,aAAa,EAAE,cAAc,EAAE,MAAM,YAAY,CAAA;AASpG;;;;;GAKG;AACH,wBAAsB,SAAS,CAAC,KAAK,EAAE,aAAa,GAAG,OAAO,CAAC,cAAc,CAAC,CA+D7E"}
@@ -0,0 +1,75 @@
1
+ import { SYNTHESIZER_SYSTEM, participantSystem, renderAnonymized, sumUsage, synthesisPrompt, } from './shared.js';
2
+ /**
3
+ * Debate: an initial independent draft round, then `rounds-1` critique rounds in which
4
+ * each participant sees the ANONYMIZED latest peer arguments and revises its own position
5
+ * (defending or conceding on the merits), and finally a neutral judge synthesizes the last
6
+ * round. Independence first, anonymized exposure, explicit disagreement, capped rounds.
7
+ */
8
+ export async function runDebate(input) {
9
+ const { participants, baseSystem, goalPrompt, generate, tags } = input;
10
+ const totalRounds = Math.max(1, Math.min(5, Math.floor(input.rounds || 2)));
11
+ const rounds = [];
12
+ const usageParts = [];
13
+ // Round 0 — independent drafts, in parallel.
14
+ let latest = await Promise.all(participants.map(async (p) => {
15
+ const { text, usage } = await generate({
16
+ model: p.model,
17
+ system: participantSystem(baseSystem, p),
18
+ prompt: goalPrompt,
19
+ temperature: 0.7,
20
+ tags,
21
+ });
22
+ usageParts.push(usage);
23
+ return { participantId: p.id, text };
24
+ }));
25
+ rounds.push({ index: 0, kind: 'draft', contributions: latest });
26
+ await input.onProgress?.({ rounds: [...rounds], status: 'running' });
27
+ // Critique rounds — each participant revises after reading the anonymized peers.
28
+ for (let r = 1; r < totalRounds; r++) {
29
+ const priorByParticipant = new Map(latest.map((c) => [c.participantId, c]));
30
+ const next = await Promise.all(participants.map(async (p) => {
31
+ const peers = latest.filter((c) => c.participantId !== p.id);
32
+ const ownPrior = priorByParticipant.get(p.id)?.text ?? '';
33
+ const prompt = debateCritiquePrompt(goalPrompt, ownPrior, peers, participants);
34
+ const { text, usage } = await generate({
35
+ model: p.model,
36
+ system: participantSystem(baseSystem, p),
37
+ prompt,
38
+ temperature: 0.5,
39
+ tags,
40
+ });
41
+ usageParts.push(usage);
42
+ return { participantId: p.id, text };
43
+ }));
44
+ latest = next;
45
+ rounds.push({ index: r, kind: 'critique', contributions: next });
46
+ await input.onProgress?.({ rounds: [...rounds], status: 'running' });
47
+ }
48
+ await input.onProgress?.({ rounds: [...rounds], status: 'synthesizing' });
49
+ const rendered = renderAnonymized(latest, participants);
50
+ const { text: synthesis, usage: synthUsage } = await generate({
51
+ model: input.synthesizer.model,
52
+ system: SYNTHESIZER_SYSTEM,
53
+ prompt: synthesisPrompt(goalPrompt, rendered, 'These are the experts’ final positions after debate. Produce the single best final result now, in exactly the format the task requires.'),
54
+ temperature: 0.2,
55
+ tags,
56
+ });
57
+ usageParts.push(synthUsage);
58
+ return { rounds, synthesis, confidence: null, dissent: [], usage: sumUsage(usageParts) };
59
+ }
60
+ function debateCritiquePrompt(goalPrompt, ownPrior, peers, participants) {
61
+ return [
62
+ 'TASK:',
63
+ goalPrompt,
64
+ '',
65
+ 'Your previous answer:',
66
+ ownPrior || '(none)',
67
+ '',
68
+ 'Other experts answered the same task as follows (anonymized):',
69
+ '',
70
+ renderAnonymized(peers, participants),
71
+ '',
72
+ 'Critique their reasoning and reconsider your own. Where a peer is more correct, adopt it; where you are right, defend it with evidence. Then give your improved, complete answer to the task (not just the diff).',
73
+ ].join('\n');
74
+ }
75
+ //# sourceMappingURL=debate.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"debate.js","sourceRoot":"","sources":["../../src/strategies/debate.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,12 @@
1
+ import type { StrategyInput, StrategyResult } from './types.js';
2
+ /**
3
+ * Ranked voting / scoring: each participant produces an independent candidate answer,
4
+ * then every participant scores ALL candidates (0..1) against the task; scores are
5
+ * aggregated deterministically (mean) and the highest-rated candidate wins. The winning
6
+ * candidate becomes the result, the mean is the confidence, and a near-tie is reported as
7
+ * dissent. Independence first; peer scoring is anonymized; aggregation is deterministic.
8
+ */
9
+ export declare function runRankedVoting(input: StrategyInput): Promise<StrategyResult>;
10
+ /** Tolerant parse of a `{ "Expert A": 0.8, ... }` score map; clamps to [0,1]. */
11
+ export declare function parseScoreMap(text: string, labels: string[]): Record<string, number>;
12
+ //# sourceMappingURL=rankedVoting.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"rankedVoting.d.ts","sourceRoot":"","sources":["../../src/strategies/rankedVoting.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAkB,aAAa,EAAE,cAAc,EAAE,MAAM,YAAY,CAAA;AAG/E;;;;;;GAMG;AACH,wBAAsB,eAAe,CAAC,KAAK,EAAE,aAAa,GAAG,OAAO,CAAC,cAAc,CAAC,CAqEnF;AAiBD,iFAAiF;AACjF,wBAAgB,aAAa,CAAC,IAAI,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,GAAG,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAkBpF"}
@@ -0,0 +1,108 @@
1
+ import { anonLabel, participantSystem, renderAnonymized, sumUsage } from './shared.js';
2
+ /**
3
+ * Ranked voting / scoring: each participant produces an independent candidate answer,
4
+ * then every participant scores ALL candidates (0..1) against the task; scores are
5
+ * aggregated deterministically (mean) and the highest-rated candidate wins. The winning
6
+ * candidate becomes the result, the mean is the confidence, and a near-tie is reported as
7
+ * dissent. Independence first; peer scoring is anonymized; aggregation is deterministic.
8
+ */
9
+ export async function runRankedVoting(input) {
10
+ const { participants, baseSystem, goalPrompt, generate, tags } = input;
11
+ const usageParts = [];
12
+ // Round 0 — independent candidates, in parallel.
13
+ const candidates = await Promise.all(participants.map(async (p) => {
14
+ const { text, usage } = await generate({
15
+ model: p.model,
16
+ system: participantSystem(baseSystem, p),
17
+ prompt: goalPrompt,
18
+ temperature: 0.7,
19
+ tags,
20
+ });
21
+ usageParts.push(usage);
22
+ return { participantId: p.id, text };
23
+ }));
24
+ const draftRound = { index: 0, kind: 'draft', contributions: candidates };
25
+ await input.onProgress?.({ rounds: [draftRound], status: 'running' });
26
+ const labels = participants.map((_, i) => anonLabel(i));
27
+ const rendered = renderAnonymized(candidates, participants);
28
+ // Round 1 — each participant scores every candidate 0..1.
29
+ const scoreContributions = await Promise.all(participants.map(async (p) => {
30
+ const { text, usage } = await generate({
31
+ model: p.model,
32
+ system: participantSystem(baseSystem, p),
33
+ prompt: scorePrompt(goalPrompt, rendered, labels),
34
+ temperature: 0.1,
35
+ tags,
36
+ });
37
+ usageParts.push(usage);
38
+ const map = parseScoreMap(text, labels);
39
+ const scores = labels.map((label) => ({
40
+ dimension: label,
41
+ value: map[label] ?? 0,
42
+ }));
43
+ return { participantId: p.id, text, scores };
44
+ }));
45
+ const scoreRound = { index: 1, kind: 'score', contributions: scoreContributions };
46
+ await input.onProgress?.({ rounds: [draftRound, scoreRound], status: 'synthesizing' });
47
+ // Deterministic aggregation: mean score per candidate across all scorers.
48
+ const means = labels.map((label) => {
49
+ const vals = scoreContributions
50
+ .map((c) => c.scores?.find((s) => s.dimension === label)?.value)
51
+ .filter((v) => typeof v === 'number');
52
+ return vals.length ? vals.reduce((a, b) => a + b, 0) / vals.length : 0;
53
+ });
54
+ let winner = 0;
55
+ for (let i = 1; i < means.length; i++)
56
+ if (means[i] > means[winner])
57
+ winner = i;
58
+ const sorted = [...means].sort((a, b) => b - a);
59
+ const dissent = sorted.length >= 2 && sorted[0] - sorted[1] < 0.1
60
+ ? [`Close vote: top candidates scored ${sorted[0].toFixed(2)} vs ${sorted[1].toFixed(2)}.`]
61
+ : [];
62
+ return {
63
+ rounds: [draftRound, scoreRound],
64
+ synthesis: candidates[winner]?.text ?? '',
65
+ confidence: means[winner] ?? null,
66
+ dissent,
67
+ usage: sumUsage(usageParts),
68
+ };
69
+ }
70
+ function scorePrompt(goalPrompt, rendered, labels) {
71
+ return [
72
+ 'TASK:',
73
+ goalPrompt,
74
+ '',
75
+ 'Candidate answers from independent experts (anonymized):',
76
+ '',
77
+ rendered,
78
+ '',
79
+ `Score how well EACH candidate solves the task, from 0 (poor) to 1 (excellent). Be discriminating. Respond with ONLY a JSON object mapping each label to its score, e.g. {${labels
80
+ .map((l) => `"${l}":0.0`)
81
+ .join(',')}} — no prose, no code fences.`,
82
+ ].join('\n');
83
+ }
84
+ /** Tolerant parse of a `{ "Expert A": 0.8, ... }` score map; clamps to [0,1]. */
85
+ export function parseScoreMap(text, labels) {
86
+ const start = text.indexOf('{');
87
+ const end = text.lastIndexOf('}');
88
+ const out = {};
89
+ if (start === -1 || end <= start)
90
+ return out;
91
+ let raw;
92
+ try {
93
+ raw = JSON.parse(text.slice(start, end + 1));
94
+ }
95
+ catch {
96
+ return out;
97
+ }
98
+ if (!raw || typeof raw !== 'object')
99
+ return out;
100
+ const obj = raw;
101
+ for (const label of labels) {
102
+ const v = obj[label];
103
+ if (typeof v === 'number' && Number.isFinite(v))
104
+ out[label] = Math.max(0, Math.min(1, v));
105
+ }
106
+ return out;
107
+ }
108
+ //# sourceMappingURL=rankedVoting.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"rankedVoting.js","sourceRoot":"","sources":["../../src/strategies/rankedVoting.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,25 @@
1
+ import type { ConsensusContribution } from '@cat-factory/kernel';
2
+ import type { ConsensusUsage, GenerateFn, ResolvedParticipant } from './types.js';
3
+ /** The default LLM call: a one-shot `generateText` tagged for the observability sink. */
4
+ export declare const defaultGenerate: GenerateFn;
5
+ export declare const ZERO_USAGE: ConsensusUsage;
6
+ export declare function addUsage(a: ConsensusUsage, b: ConsensusUsage): ConsensusUsage;
7
+ export declare function sumUsage(parts: ConsensusUsage[]): ConsensusUsage;
8
+ /** Stable anonymous label for a participant index, so peers can't anchor on identity. */
9
+ export declare function anonLabel(index: number): string;
10
+ /** The per-participant system prompt: base role + their distinct perspective framing. */
11
+ export declare function participantSystem(base: string, participant: ResolvedParticipant): string;
12
+ /**
13
+ * Render a set of contributions anonymously for a critique/synthesis prompt. `participants`
14
+ * provides the index order so labels are stable across rounds.
15
+ */
16
+ export declare function renderAnonymized(contributions: ConsensusContribution[], participants: ResolvedParticipant[]): string;
17
+ /** The neutral synthesizer/judge system prompt. */
18
+ export declare const SYNTHESIZER_SYSTEM: string;
19
+ /**
20
+ * Build the synthesizer prompt: the original goal plus the anonymized contributions to
21
+ * merge. `formatReminder` re-states the required output format (e.g. JSON for an
22
+ * estimator) so the synthesis stays consumable by the engine.
23
+ */
24
+ export declare function synthesisPrompt(goalPrompt: string, rendered: string, formatReminder: string): string;
25
+ //# sourceMappingURL=shared.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"shared.d.ts","sourceRoot":"","sources":["../../src/strategies/shared.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,qBAAqB,EAAE,MAAM,qBAAqB,CAAA;AAChE,OAAO,KAAK,EACV,cAAc,EAEd,UAAU,EAEV,mBAAmB,EACpB,MAAM,YAAY,CAAA;AAMnB,yFAAyF;AACzF,eAAO,MAAM,eAAe,EAAE,UAiB7B,CAAA;AAED,eAAO,MAAM,UAAU,EAAE,cAAoD,CAAA;AAE7E,wBAAgB,QAAQ,CAAC,CAAC,EAAE,cAAc,EAAE,CAAC,EAAE,cAAc,GAAG,cAAc,CAK7E;AAED,wBAAgB,QAAQ,CAAC,KAAK,EAAE,cAAc,EAAE,GAAG,cAAc,CAEhE;AAED,yFAAyF;AACzF,wBAAgB,SAAS,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM,CAE/C;AAED,yFAAyF;AACzF,wBAAgB,iBAAiB,CAAC,IAAI,EAAE,MAAM,EAAE,WAAW,EAAE,mBAAmB,GAAG,MAAM,CAGxF;AAED;;;GAGG;AACH,wBAAgB,gBAAgB,CAC9B,aAAa,EAAE,qBAAqB,EAAE,EACtC,YAAY,EAAE,mBAAmB,EAAE,GAClC,MAAM,CAOR;AAED,mDAAmD;AACnD,eAAO,MAAM,kBAAkB,QAKpB,CAAA;AAEX;;;;GAIG;AACH,wBAAgB,eAAe,CAC7B,UAAU,EAAE,MAAM,EAClB,QAAQ,EAAE,MAAM,EAChB,cAAc,EAAE,MAAM,GACrB,MAAM,CAWR"}
@@ -0,0 +1,81 @@
1
+ import { generateText } from 'ai';
2
+ import { catFactoryObservability } from '@cat-factory/kernel';
3
+ // Shared helpers for the consensus strategies: the default Vercel-AI-SDK `generate`
4
+ // implementation, usage accumulation, anonymization (so peers judge ideas, not authors),
5
+ // and the participant/synthesizer prompt builders that encode the debate best-practices.
6
+ /** The default LLM call: a one-shot `generateText` tagged for the observability sink. */
7
+ export const defaultGenerate = async (args) => {
8
+ const { text, usage } = await generateText({
9
+ model: args.model,
10
+ system: args.system,
11
+ prompt: args.prompt,
12
+ ...(args.temperature !== undefined ? { temperature: args.temperature } : {}),
13
+ ...(args.maxOutputTokens !== undefined ? { maxOutputTokens: args.maxOutputTokens } : {}),
14
+ providerOptions: catFactoryObservability({
15
+ agentKind: args.tags.agentKind,
16
+ workspaceId: args.tags.workspaceId,
17
+ executionId: args.tags.executionId,
18
+ }),
19
+ });
20
+ return {
21
+ text: text.trim(),
22
+ usage: { inputTokens: usage.inputTokens ?? 0, outputTokens: usage.outputTokens ?? 0 },
23
+ };
24
+ };
25
+ export const ZERO_USAGE = { inputTokens: 0, outputTokens: 0 };
26
+ export function addUsage(a, b) {
27
+ return {
28
+ inputTokens: a.inputTokens + b.inputTokens,
29
+ outputTokens: a.outputTokens + b.outputTokens,
30
+ };
31
+ }
32
+ export function sumUsage(parts) {
33
+ return parts.reduce(addUsage, ZERO_USAGE);
34
+ }
35
+ /** Stable anonymous label for a participant index, so peers can't anchor on identity. */
36
+ export function anonLabel(index) {
37
+ return `Expert ${String.fromCharCode(65 + (index % 26))}`;
38
+ }
39
+ /** The per-participant system prompt: base role + their distinct perspective framing. */
40
+ export function participantSystem(base, participant) {
41
+ if (!participant.systemFraming)
42
+ return base;
43
+ return `${base}\n\nYour assigned perspective as the "${participant.role}": ${participant.systemFraming}\nArgue your perspective rigorously and honestly; do not merely agree.`;
44
+ }
45
+ /**
46
+ * Render a set of contributions anonymously for a critique/synthesis prompt. `participants`
47
+ * provides the index order so labels are stable across rounds.
48
+ */
49
+ export function renderAnonymized(contributions, participants) {
50
+ return contributions
51
+ .map((c) => {
52
+ const idx = participants.findIndex((p) => p.id === c.participantId);
53
+ return `### ${anonLabel(idx < 0 ? 0 : idx)}\n${c.text}`;
54
+ })
55
+ .join('\n\n');
56
+ }
57
+ /** The neutral synthesizer/judge system prompt. */
58
+ export const SYNTHESIZER_SYSTEM = [
59
+ 'You are a neutral synthesizer chairing a panel of independent experts who each tackled the SAME task.',
60
+ 'Your job is to produce ONE final, polished result that is better than any single contribution.',
61
+ 'Combine the strongest, best-justified points; resolve contradictions on the merits (not by vote-counting or splitting the difference); and silently drop weak or unsupported claims.',
62
+ 'Do not mention the experts, the panel, or that a synthesis occurred — output only the final result itself, in exactly the format the task requires.',
63
+ ].join(' ');
64
+ /**
65
+ * Build the synthesizer prompt: the original goal plus the anonymized contributions to
66
+ * merge. `formatReminder` re-states the required output format (e.g. JSON for an
67
+ * estimator) so the synthesis stays consumable by the engine.
68
+ */
69
+ export function synthesisPrompt(goalPrompt, rendered, formatReminder) {
70
+ return [
71
+ 'TASK:',
72
+ goalPrompt,
73
+ '',
74
+ 'The independent expert responses to merge:',
75
+ '',
76
+ rendered,
77
+ '',
78
+ formatReminder,
79
+ ].join('\n');
80
+ }
81
+ //# sourceMappingURL=shared.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"shared.js","sourceRoot":"","sources":["../../src/strategies/shared.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,9 @@
1
+ import type { StrategyInput, StrategyResult } from './types.js';
2
+ /**
3
+ * Specialist panel: every participant answers the goal INDEPENDENTLY and in parallel
4
+ * (blind to each other — no anchoring/groupthink), then a neutral synthesizer merges the
5
+ * drafts into one polished result. The single highest-leverage consensus shape: diversity
6
+ * of role + model, independence before exposure, neutral synthesis.
7
+ */
8
+ export declare function runSpecialistPanel(input: StrategyInput): Promise<StrategyResult>;
9
+ //# sourceMappingURL=specialistPanel.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"specialistPanel.d.ts","sourceRoot":"","sources":["../../src/strategies/specialistPanel.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,aAAa,EAAE,cAAc,EAAE,MAAM,YAAY,CAAA;AAS/D;;;;;GAKG;AACH,wBAAsB,kBAAkB,CAAC,KAAK,EAAE,aAAa,GAAG,OAAO,CAAC,cAAc,CAAC,CA2CtF"}
@@ -0,0 +1,42 @@
1
+ import { SYNTHESIZER_SYSTEM, participantSystem, renderAnonymized, sumUsage, synthesisPrompt, } from './shared.js';
2
+ /**
3
+ * Specialist panel: every participant answers the goal INDEPENDENTLY and in parallel
4
+ * (blind to each other — no anchoring/groupthink), then a neutral synthesizer merges the
5
+ * drafts into one polished result. The single highest-leverage consensus shape: diversity
6
+ * of role + model, independence before exposure, neutral synthesis.
7
+ */
8
+ export async function runSpecialistPanel(input) {
9
+ const { participants, baseSystem, goalPrompt, generate, tags } = input;
10
+ const drafts = await Promise.all(participants.map(async (p) => {
11
+ const { text, usage } = await generate({
12
+ model: p.model,
13
+ system: participantSystem(baseSystem, p),
14
+ prompt: goalPrompt,
15
+ temperature: 0.7,
16
+ tags,
17
+ });
18
+ return { contribution: { participantId: p.id, text }, usage };
19
+ }));
20
+ const draftRound = {
21
+ index: 0,
22
+ kind: 'draft',
23
+ contributions: drafts.map((d) => d.contribution),
24
+ };
25
+ await input.onProgress?.({ rounds: [draftRound], status: 'synthesizing' });
26
+ const rendered = renderAnonymized(draftRound.contributions, participants);
27
+ const { text: synthesis, usage: synthUsage } = await generate({
28
+ model: input.synthesizer.model,
29
+ system: SYNTHESIZER_SYSTEM,
30
+ prompt: synthesisPrompt(goalPrompt, rendered, 'Produce the single best final result now, in exactly the format the task requires.'),
31
+ temperature: 0.2,
32
+ tags,
33
+ });
34
+ return {
35
+ rounds: [draftRound],
36
+ synthesis,
37
+ confidence: null,
38
+ dissent: [],
39
+ usage: sumUsage([...drafts.map((d) => d.usage), synthUsage]),
40
+ };
41
+ }
42
+ //# sourceMappingURL=specialistPanel.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"specialistPanel.js","sourceRoot":"","sources":["../../src/strategies/specialistPanel.ts"],"names":[],"mappings":"AAEA,OAAO,EACL,kBAAkB,EAClB,iBAAiB,EACjB,gBAAgB,EAChB,QAAQ,EACR,eAAe,GAChB,MAAM,aAAa,CAAA;AAEpB;;;;;GAKG;AACH,MAAM,CAAC,KAAK,UAAU,kBAAkB,CAAC,KAAoB;IAC3D,MAAM,EAAE,YAAY,EAAE,UAAU,EAAE,UAAU,EAAE,QAAQ,EAAE,IAAI,EAAE,GAAG,KAAK,CAAA;IAEtE,MAAM,MAAM,GAAG,MAAM,OAAO,CAAC,GAAG,CAC9B,YAAY,CAAC,GAAG,CAAC,KAAK,EAAE,CAAC,EAAE,EAAE;QAC3B,MAAM,EAAE,IAAI,EAAE,KAAK,EAAE,GAAG,MAAM,QAAQ,CAAC;YACrC,KAAK,EAAE,CAAC,CAAC,KAAK;YACd,MAAM,EAAE,iBAAiB,CAAC,UAAU,EAAE,CAAC,CAAC;YACxC,MAAM,EAAE,UAAU;YAClB,WAAW,EAAE,GAAG;YAChB,IAAI;SACL,CAAC,CAAA;QACF,OAAO,EAAE,YAAY,EAAE,EAAE,aAAa,EAAE,CAAC,CAAC,EAAE,EAAE,IAAI,EAA2B,EAAE,KAAK,EAAE,CAAA;IACxF,CAAC,CAAC,CACH,CAAA;IAED,MAAM,UAAU,GAAmB;QACjC,KAAK,EAAE,CAAC;QACR,IAAI,EAAE,OAAO;QACb,aAAa,EAAE,MAAM,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,YAAY,CAAC;KACjD,CAAA;IACD,MAAM,KAAK,CAAC,UAAU,EAAE,CAAC,EAAE,MAAM,EAAE,CAAC,UAAU,CAAC,EAAE,MAAM,EAAE,cAAc,EAAE,CAAC,CAAA;IAE1E,MAAM,QAAQ,GAAG,gBAAgB,CAAC,UAAU,CAAC,aAAa,EAAE,YAAY,CAAC,CAAA;IACzE,MAAM,EAAE,IAAI,EAAE,SAAS,EAAE,KAAK,EAAE,UAAU,EAAE,GAAG,MAAM,QAAQ,CAAC;QAC5D,KAAK,EAAE,KAAK,CAAC,WAAW,CAAC,KAAK;QAC9B,MAAM,EAAE,kBAAkB;QAC1B,MAAM,EAAE,eAAe,CACrB,UAAU,EACV,QAAQ,EACR,oFAAoF,CACrF;QACD,WAAW,EAAE,GAAG;QAChB,IAAI;KACL,CAAC,CAAA;IAEF,OAAO;QACL,MAAM,EAAE,CAAC,UAAU,CAAC;QACpB,SAAS;QACT,UAAU,EAAE,IAAI;QAChB,OAAO,EAAE,EAAE;QACX,KAAK,EAAE,QAAQ,CAAC,CAAC,GAAG,MAAM,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,KAAK,CAAC,EAAE,UAAU,CAAC,CAAC;KAC7D,CAAA;AACH,CAAC"}
@@ -0,0 +1,71 @@
1
+ import type { LanguageModel } from 'ai';
2
+ import type { ConsensusRound, ConsensusSessionStatus } from '@cat-factory/kernel';
3
+ /** Token usage accumulated across a strategy's LLM calls. */
4
+ export interface ConsensusUsage {
5
+ inputTokens: number;
6
+ outputTokens: number;
7
+ }
8
+ /** A participant with its model resolved to a concrete handle. */
9
+ export interface ResolvedParticipant {
10
+ id: string;
11
+ role: string;
12
+ systemFraming?: string;
13
+ model: LanguageModel;
14
+ /** `provider:model`, for the transcript + synthesizer label. */
15
+ modelLabel: string;
16
+ }
17
+ /** Observability tags threaded into every sub-call's provider options. */
18
+ export interface ObsTags {
19
+ agentKind: string;
20
+ workspaceId?: string;
21
+ executionId?: string;
22
+ }
23
+ export interface GenerateArgs {
24
+ model: LanguageModel;
25
+ system: string;
26
+ prompt: string;
27
+ temperature?: number;
28
+ maxOutputTokens?: number;
29
+ tags: ObsTags;
30
+ }
31
+ export interface GenerateResult {
32
+ text: string;
33
+ usage: ConsensusUsage;
34
+ }
35
+ /** Inject the LLM call so strategies stay testable; defaults to {@link defaultGenerate}. */
36
+ export type GenerateFn = (args: GenerateArgs) => Promise<GenerateResult>;
37
+ export interface StrategyInput {
38
+ agentKind: string;
39
+ /** The base role/system prompt of the underlying agent kind. */
40
+ baseSystem: string;
41
+ /** The user prompt describing the goal (the same one the standard agent would get). */
42
+ goalPrompt: string;
43
+ participants: ResolvedParticipant[];
44
+ synthesizer: {
45
+ model: LanguageModel;
46
+ modelLabel: string;
47
+ };
48
+ /** Debate rounds (incl. the initial draft); clamped/ignored by non-debate strategies. */
49
+ rounds: number;
50
+ generate: GenerateFn;
51
+ tags: ObsTags;
52
+ /**
53
+ * Stream progress so the executor can persist + push the live transcript after each
54
+ * round / on synthesis. Best-effort; failures are swallowed by the executor's wiring.
55
+ */
56
+ onProgress?: (update: {
57
+ rounds: ConsensusRound[];
58
+ status: ConsensusSessionStatus;
59
+ }) => Promise<void>;
60
+ }
61
+ export interface StrategyResult {
62
+ rounds: ConsensusRound[];
63
+ /** The final synthesized artifact — becomes the step's output. */
64
+ synthesis: string;
65
+ /** Aggregate confidence (0..1) when the strategy yields one (ranked-voting), else null. */
66
+ confidence: number | null;
67
+ /** Notable unresolved disagreements surfaced during the process. */
68
+ dissent: string[];
69
+ usage: ConsensusUsage;
70
+ }
71
+ //# sourceMappingURL=types.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../src/strategies/types.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,IAAI,CAAA;AACvC,OAAO,KAAK,EAAE,cAAc,EAAE,sBAAsB,EAAE,MAAM,qBAAqB,CAAA;AAOjF,6DAA6D;AAC7D,MAAM,WAAW,cAAc;IAC7B,WAAW,EAAE,MAAM,CAAA;IACnB,YAAY,EAAE,MAAM,CAAA;CACrB;AAED,kEAAkE;AAClE,MAAM,WAAW,mBAAmB;IAClC,EAAE,EAAE,MAAM,CAAA;IACV,IAAI,EAAE,MAAM,CAAA;IACZ,aAAa,CAAC,EAAE,MAAM,CAAA;IACtB,KAAK,EAAE,aAAa,CAAA;IACpB,gEAAgE;IAChE,UAAU,EAAE,MAAM,CAAA;CACnB;AAED,0EAA0E;AAC1E,MAAM,WAAW,OAAO;IACtB,SAAS,EAAE,MAAM,CAAA;IACjB,WAAW,CAAC,EAAE,MAAM,CAAA;IACpB,WAAW,CAAC,EAAE,MAAM,CAAA;CACrB;AAED,MAAM,WAAW,YAAY;IAC3B,KAAK,EAAE,aAAa,CAAA;IACpB,MAAM,EAAE,MAAM,CAAA;IACd,MAAM,EAAE,MAAM,CAAA;IACd,WAAW,CAAC,EAAE,MAAM,CAAA;IACpB,eAAe,CAAC,EAAE,MAAM,CAAA;IACxB,IAAI,EAAE,OAAO,CAAA;CACd;AAED,MAAM,WAAW,cAAc;IAC7B,IAAI,EAAE,MAAM,CAAA;IACZ,KAAK,EAAE,cAAc,CAAA;CACtB;AAED,4FAA4F;AAC5F,MAAM,MAAM,UAAU,GAAG,CAAC,IAAI,EAAE,YAAY,KAAK,OAAO,CAAC,cAAc,CAAC,CAAA;AAExE,MAAM,WAAW,aAAa;IAC5B,SAAS,EAAE,MAAM,CAAA;IACjB,gEAAgE;IAChE,UAAU,EAAE,MAAM,CAAA;IAClB,uFAAuF;IACvF,UAAU,EAAE,MAAM,CAAA;IAClB,YAAY,EAAE,mBAAmB,EAAE,CAAA;IACnC,WAAW,EAAE;QAAE,KAAK,EAAE,aAAa,CAAC;QAAC,UAAU,EAAE,MAAM,CAAA;KAAE,CAAA;IACzD,yFAAyF;IACzF,MAAM,EAAE,MAAM,CAAA;IACd,QAAQ,EAAE,UAAU,CAAA;IACpB,IAAI,EAAE,OAAO,CAAA;IACb;;;OAGG;IACH,UAAU,CAAC,EAAE,CAAC,MAAM,EAAE;QACpB,MAAM,EAAE,cAAc,EAAE,CAAA;QACxB,MAAM,EAAE,sBAAsB,CAAA;KAC/B,KAAK,OAAO,CAAC,IAAI,CAAC,CAAA;CACpB;AAED,MAAM,WAAW,cAAc;IAC7B,MAAM,EAAE,cAAc,EAAE,CAAA;IACxB,kEAAkE;IAClE,SAAS,EAAE,MAAM,CAAA;IACjB,2FAA2F;IAC3F,UAAU,EAAE,MAAM,GAAG,IAAI,CAAA;IACzB,oEAAoE;IACpE,OAAO,EAAE,MAAM,EAAE,CAAA;IACjB,KAAK,EAAE,cAAc,CAAA;CACtB"}
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=types.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.js","sourceRoot":"","sources":["../../src/strategies/types.ts"],"names":[],"mappings":""}
@@ -0,0 +1,35 @@
1
+ import type { AgentKind, ConsensusStrategy } from '@cat-factory/kernel';
2
+ export declare const SPECIALIST_PANEL_CAPABLE = "specialist-panel-capable";
3
+ export declare const DEBATE_CAPABLE = "debate-capable";
4
+ export declare const RANKED_VOTING_CAPABLE = "ranked-voting-capable";
5
+ /** Map a strategy to the trait that gates its eligibility. */
6
+ export declare const STRATEGY_TRAIT: Record<ConsensusStrategy, string>;
7
+ /** All consensus capability traits. */
8
+ export declare const CONSENSUS_TRAITS: readonly ["specialist-panel-capable", "debate-capable", "ranked-voting-capable"];
9
+ /**
10
+ * The default-eligible kinds, each carrying all three consensus traits. A deployment
11
+ * can extend this with {@link assignAgentTraits}. NOTE: `architect` and `analysis` run
12
+ * in a container against a real checkout in their standard mode; in CONSENSUS mode they
13
+ * reason inline over the provided context (spec + requirements + prior outputs) rather
14
+ * than exploring the checkout — a deliberate trade made worthwhile by the gating, which
15
+ * only triggers consensus for high-complexity/risk/impact tasks.
16
+ *
17
+ * - architect → a well-reasoned architecture document
18
+ * - analysis → a deep investigation / aggregate of observations
19
+ * - reviewer → a rigorous, high-confidence code review (the companion verdict)
20
+ * - task-estimator → an accurate complexity/risk/impact estimate (ranked-scoring)
21
+ */
22
+ export declare const DEFAULT_CONSENSUS_ELIGIBLE_KINDS: AgentKind[];
23
+ /**
24
+ * Register the consensus capability traits and assign them to the default-eligible
25
+ * kinds. A startup import side-effect each facade calls when consensus is enabled,
26
+ * mirroring the custom-agent / model-provider registry seams. Idempotent.
27
+ *
28
+ * @param kinds override the default-eligible set (e.g. a deployment's own kinds).
29
+ */
30
+ export declare function registerConsensusTraits(kinds?: AgentKind[]): void;
31
+ /** The consensus strategies a kind is eligible for, derived from its traits. */
32
+ export declare function consensusStrategiesFor(kind: AgentKind): ConsensusStrategy[];
33
+ /** Whether a kind is eligible for at least one consensus strategy. */
34
+ export declare function isConsensusEligible(kind: AgentKind): boolean;
35
+ //# sourceMappingURL=traits.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"traits.d.ts","sourceRoot":"","sources":["../src/traits.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,SAAS,EAAE,iBAAiB,EAAE,MAAM,qBAAqB,CAAA;AAUvE,eAAO,MAAM,wBAAwB,6BAA6B,CAAA;AAClE,eAAO,MAAM,cAAc,mBAAmB,CAAA;AAC9C,eAAO,MAAM,qBAAqB,0BAA0B,CAAA;AAE5D,8DAA8D;AAC9D,eAAO,MAAM,cAAc,EAAE,MAAM,CAAC,iBAAiB,EAAE,MAAM,CAI5D,CAAA;AAED,uCAAuC;AACvC,eAAO,MAAM,gBAAgB,kFAInB,CAAA;AAEV;;;;;;;;;;;;GAYG;AACH,eAAO,MAAM,gCAAgC,EAAE,SAAS,EAKvD,CAAA;AAED;;;;;;GAMG;AACH,wBAAgB,uBAAuB,CACrC,KAAK,GAAE,SAAS,EAAqC,GACpD,IAAI,CAGN;AAED,gFAAgF;AAChF,wBAAgB,sBAAsB,CAAC,IAAI,EAAE,SAAS,GAAG,iBAAiB,EAAE,CAK3E;AAED,sEAAsE;AACtE,wBAAgB,mBAAmB,CAAC,IAAI,EAAE,SAAS,GAAG,OAAO,CAE5D"}
package/dist/traits.js ADDED
@@ -0,0 +1,64 @@
1
+ import { assignAgentTraits, registerAgentTrait, traitsFor } from '@cat-factory/agents';
2
+ import { TASK_ESTIMATOR_AGENT_KIND } from '@cat-factory/agents';
3
+ // The group of consensus CAPABILITY traits an agent kind can carry. Each marks the
4
+ // kind eligible for one consensus strategy: when a step's kind carries the trait, the
5
+ // pipeline builder offers that strategy under "Enable Consensus". They are pure marker
6
+ // traits (no prompt guidance — their effect lives in the consensus executor + the
7
+ // builder UI), registered alongside the built-in `code-aware` / `spec-aware` traits.
8
+ export const SPECIALIST_PANEL_CAPABLE = 'specialist-panel-capable';
9
+ export const DEBATE_CAPABLE = 'debate-capable';
10
+ export const RANKED_VOTING_CAPABLE = 'ranked-voting-capable';
11
+ /** Map a strategy to the trait that gates its eligibility. */
12
+ export const STRATEGY_TRAIT = {
13
+ 'specialist-panel': SPECIALIST_PANEL_CAPABLE,
14
+ debate: DEBATE_CAPABLE,
15
+ 'ranked-voting': RANKED_VOTING_CAPABLE,
16
+ };
17
+ /** All consensus capability traits. */
18
+ export const CONSENSUS_TRAITS = [
19
+ SPECIALIST_PANEL_CAPABLE,
20
+ DEBATE_CAPABLE,
21
+ RANKED_VOTING_CAPABLE,
22
+ ];
23
+ /**
24
+ * The default-eligible kinds, each carrying all three consensus traits. A deployment
25
+ * can extend this with {@link assignAgentTraits}. NOTE: `architect` and `analysis` run
26
+ * in a container against a real checkout in their standard mode; in CONSENSUS mode they
27
+ * reason inline over the provided context (spec + requirements + prior outputs) rather
28
+ * than exploring the checkout — a deliberate trade made worthwhile by the gating, which
29
+ * only triggers consensus for high-complexity/risk/impact tasks.
30
+ *
31
+ * - architect → a well-reasoned architecture document
32
+ * - analysis → a deep investigation / aggregate of observations
33
+ * - reviewer → a rigorous, high-confidence code review (the companion verdict)
34
+ * - task-estimator → an accurate complexity/risk/impact estimate (ranked-scoring)
35
+ */
36
+ export const DEFAULT_CONSENSUS_ELIGIBLE_KINDS = [
37
+ 'architect',
38
+ 'analysis',
39
+ 'reviewer',
40
+ TASK_ESTIMATOR_AGENT_KIND,
41
+ ];
42
+ /**
43
+ * Register the consensus capability traits and assign them to the default-eligible
44
+ * kinds. A startup import side-effect each facade calls when consensus is enabled,
45
+ * mirroring the custom-agent / model-provider registry seams. Idempotent.
46
+ *
47
+ * @param kinds override the default-eligible set (e.g. a deployment's own kinds).
48
+ */
49
+ export function registerConsensusTraits(kinds = DEFAULT_CONSENSUS_ELIGIBLE_KINDS) {
50
+ for (const trait of CONSENSUS_TRAITS)
51
+ registerAgentTrait({ id: trait });
52
+ for (const kind of kinds)
53
+ assignAgentTraits(kind, CONSENSUS_TRAITS);
54
+ }
55
+ /** The consensus strategies a kind is eligible for, derived from its traits. */
56
+ export function consensusStrategiesFor(kind) {
57
+ const traits = traitsFor(kind);
58
+ return Object.keys(STRATEGY_TRAIT).filter((s) => traits.has(STRATEGY_TRAIT[s]));
59
+ }
60
+ /** Whether a kind is eligible for at least one consensus strategy. */
61
+ export function isConsensusEligible(kind) {
62
+ return consensusStrategiesFor(kind).length > 0;
63
+ }
64
+ //# sourceMappingURL=traits.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"traits.js","sourceRoot":"","sources":["../src/traits.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,iBAAiB,EAAE,kBAAkB,EAAE,SAAS,EAAE,MAAM,qBAAqB,CAAA;AACtF,OAAO,EAAE,yBAAyB,EAAE,MAAM,qBAAqB,CAAA;AAE/D,mFAAmF;AACnF,sFAAsF;AACtF,uFAAuF;AACvF,kFAAkF;AAClF,qFAAqF;AAErF,MAAM,CAAC,MAAM,wBAAwB,GAAG,0BAA0B,CAAA;AAClE,MAAM,CAAC,MAAM,cAAc,GAAG,gBAAgB,CAAA;AAC9C,MAAM,CAAC,MAAM,qBAAqB,GAAG,uBAAuB,CAAA;AAE5D,8DAA8D;AAC9D,MAAM,CAAC,MAAM,cAAc,GAAsC;IAC/D,kBAAkB,EAAE,wBAAwB;IAC5C,MAAM,EAAE,cAAc;IACtB,eAAe,EAAE,qBAAqB;CACvC,CAAA;AAED,uCAAuC;AACvC,MAAM,CAAC,MAAM,gBAAgB,GAAG;IAC9B,wBAAwB;IACxB,cAAc;IACd,qBAAqB;CACb,CAAA;AAEV;;;;;;;;;;;;GAYG;AACH,MAAM,CAAC,MAAM,gCAAgC,GAAgB;IAC3D,WAAW;IACX,UAAU;IACV,UAAU;IACV,yBAAyB;CAC1B,CAAA;AAED;;;;;;GAMG;AACH,MAAM,UAAU,uBAAuB,CACrC,KAAK,GAAgB,gCAAgC;IAErD,KAAK,MAAM,KAAK,IAAI,gBAAgB;QAAE,kBAAkB,CAAC,EAAE,EAAE,EAAE,KAAK,EAAE,CAAC,CAAA;IACvE,KAAK,MAAM,IAAI,IAAI,KAAK;QAAE,iBAAiB,CAAC,IAAI,EAAE,gBAAgB,CAAC,CAAA;AACrE,CAAC;AAED,gFAAgF;AAChF,MAAM,UAAU,sBAAsB,CAAC,IAAe;IACpD,MAAM,MAAM,GAAG,SAAS,CAAC,IAAI,CAAC,CAAA;IAC9B,OAAQ,MAAM,CAAC,IAAI,CAAC,cAAc,CAAyB,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CACvE,MAAM,CAAC,GAAG,CAAC,cAAc,CAAC,CAAC,CAAC,CAAC,CAC9B,CAAA;AACH,CAAC;AAED,sEAAsE;AACtE,MAAM,UAAU,mBAAmB,CAAC,IAAe;IACjD,OAAO,sBAAsB,CAAC,IAAI,CAAC,CAAC,MAAM,GAAG,CAAC,CAAA;AAChD,CAAC"}
package/package.json ADDED
@@ -0,0 +1,37 @@
1
+ {
2
+ "name": "@cat-factory/consensus",
3
+ "version": "0.6.0",
4
+ "description": "Optional consensus-orchestration mechanism (specialist panel / debate / ranked voting) for cat-factory agent steps, with task-estimate gating.",
5
+ "files": [
6
+ "dist"
7
+ ],
8
+ "type": "module",
9
+ "main": "./dist/index.js",
10
+ "types": "./dist/index.d.ts",
11
+ "exports": {
12
+ ".": {
13
+ "types": "./dist/index.d.ts",
14
+ "default": "./dist/index.js"
15
+ },
16
+ "./package.json": "./package.json"
17
+ },
18
+ "publishConfig": {
19
+ "access": "public"
20
+ },
21
+ "dependencies": {
22
+ "ai": "^6.0.208",
23
+ "@cat-factory/agents": "0.6.0",
24
+ "@cat-factory/contracts": "0.6.0",
25
+ "@cat-factory/kernel": "0.6.0"
26
+ },
27
+ "devDependencies": {
28
+ "typescript": "7.0.1-rc",
29
+ "vitest": "^4.1.9"
30
+ },
31
+ "scripts": {
32
+ "build": "tsc -b tsconfig.build.json",
33
+ "typecheck": "tsc -p tsconfig.json --noEmit",
34
+ "test": "vitest run",
35
+ "test:run": "vitest run"
36
+ }
37
+ }