coterie 0.1.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 (203) hide show
  1. package/README.md +137 -0
  2. package/dist/adapters/base.d.ts +56 -0
  3. package/dist/adapters/base.d.ts.map +1 -0
  4. package/dist/adapters/base.js +176 -0
  5. package/dist/adapters/base.js.map +1 -0
  6. package/dist/adapters/claudeCode.d.ts +11 -0
  7. package/dist/adapters/claudeCode.d.ts.map +1 -0
  8. package/dist/adapters/claudeCode.js +65 -0
  9. package/dist/adapters/claudeCode.js.map +1 -0
  10. package/dist/adapters/codex.d.ts +10 -0
  11. package/dist/adapters/codex.d.ts.map +1 -0
  12. package/dist/adapters/codex.js +51 -0
  13. package/dist/adapters/codex.js.map +1 -0
  14. package/dist/adapters/cursor.d.ts +16 -0
  15. package/dist/adapters/cursor.d.ts.map +1 -0
  16. package/dist/adapters/cursor.js +47 -0
  17. package/dist/adapters/cursor.js.map +1 -0
  18. package/dist/adapters/fake.d.ts +19 -0
  19. package/dist/adapters/fake.d.ts.map +1 -0
  20. package/dist/adapters/fake.js +41 -0
  21. package/dist/adapters/fake.js.map +1 -0
  22. package/dist/adapters/index.d.ts +11 -0
  23. package/dist/adapters/index.d.ts.map +1 -0
  24. package/dist/adapters/index.js +11 -0
  25. package/dist/adapters/index.js.map +1 -0
  26. package/dist/adapters/stream.d.ts +6 -0
  27. package/dist/adapters/stream.d.ts.map +1 -0
  28. package/dist/adapters/stream.js +20 -0
  29. package/dist/adapters/stream.js.map +1 -0
  30. package/dist/chat/configs.d.ts +18 -0
  31. package/dist/chat/configs.d.ts.map +1 -0
  32. package/dist/chat/configs.js +71 -0
  33. package/dist/chat/configs.js.map +1 -0
  34. package/dist/chat/doctor.d.ts +16 -0
  35. package/dist/chat/doctor.d.ts.map +1 -0
  36. package/dist/chat/doctor.js +43 -0
  37. package/dist/chat/doctor.js.map +1 -0
  38. package/dist/chat/finalizer.d.ts +25 -0
  39. package/dist/chat/finalizer.d.ts.map +1 -0
  40. package/dist/chat/finalizer.js +52 -0
  41. package/dist/chat/finalizer.js.map +1 -0
  42. package/dist/chat/preflight.d.ts +37 -0
  43. package/dist/chat/preflight.d.ts.map +1 -0
  44. package/dist/chat/preflight.js +115 -0
  45. package/dist/chat/preflight.js.map +1 -0
  46. package/dist/chat/render.d.ts +21 -0
  47. package/dist/chat/render.d.ts.map +1 -0
  48. package/dist/chat/render.js +113 -0
  49. package/dist/chat/render.js.map +1 -0
  50. package/dist/chat/repl.d.ts +9 -0
  51. package/dist/chat/repl.d.ts.map +1 -0
  52. package/dist/chat/repl.js +275 -0
  53. package/dist/chat/repl.js.map +1 -0
  54. package/dist/chat/trace.d.ts +29 -0
  55. package/dist/chat/trace.d.ts.map +1 -0
  56. package/dist/chat/trace.js +132 -0
  57. package/dist/chat/trace.js.map +1 -0
  58. package/dist/chat/transcript.d.ts +15 -0
  59. package/dist/chat/transcript.d.ts.map +1 -0
  60. package/dist/chat/transcript.js +39 -0
  61. package/dist/chat/transcript.js.map +1 -0
  62. package/dist/cli.d.ts +5 -0
  63. package/dist/cli.d.ts.map +1 -0
  64. package/dist/cli.js +134 -0
  65. package/dist/cli.js.map +1 -0
  66. package/dist/config.d.ts +2 -0
  67. package/dist/config.d.ts.map +1 -0
  68. package/dist/config.js +52 -0
  69. package/dist/config.js.map +1 -0
  70. package/dist/core/annotation.d.ts +22 -0
  71. package/dist/core/annotation.d.ts.map +1 -0
  72. package/dist/core/annotation.js +45 -0
  73. package/dist/core/annotation.js.map +1 -0
  74. package/dist/core/compile.d.ts +3 -0
  75. package/dist/core/compile.d.ts.map +1 -0
  76. package/dist/core/compile.js +9 -0
  77. package/dist/core/compile.js.map +1 -0
  78. package/dist/core/executor.d.ts +32 -0
  79. package/dist/core/executor.d.ts.map +1 -0
  80. package/dist/core/executor.js +73 -0
  81. package/dist/core/executor.js.map +1 -0
  82. package/dist/core/json.d.ts +9 -0
  83. package/dist/core/json.d.ts.map +1 -0
  84. package/dist/core/json.js +49 -0
  85. package/dist/core/json.js.map +1 -0
  86. package/dist/core/llm/base.d.ts +9 -0
  87. package/dist/core/llm/base.d.ts.map +1 -0
  88. package/dist/core/llm/base.js +3 -0
  89. package/dist/core/llm/base.js.map +1 -0
  90. package/dist/core/llm/build.d.ts +16 -0
  91. package/dist/core/llm/build.d.ts.map +1 -0
  92. package/dist/core/llm/build.js +34 -0
  93. package/dist/core/llm/build.js.map +1 -0
  94. package/dist/core/llm/claudeCli.d.ts +20 -0
  95. package/dist/core/llm/claudeCli.d.ts.map +1 -0
  96. package/dist/core/llm/claudeCli.js +57 -0
  97. package/dist/core/llm/claudeCli.js.map +1 -0
  98. package/dist/core/llm/codexCli.d.ts +13 -0
  99. package/dist/core/llm/codexCli.d.ts.map +1 -0
  100. package/dist/core/llm/codexCli.js +30 -0
  101. package/dist/core/llm/codexCli.js.map +1 -0
  102. package/dist/core/llm/cursorCli.d.ts +13 -0
  103. package/dist/core/llm/cursorCli.d.ts.map +1 -0
  104. package/dist/core/llm/cursorCli.js +27 -0
  105. package/dist/core/llm/cursorCli.js.map +1 -0
  106. package/dist/core/llm/index.d.ts +5 -0
  107. package/dist/core/llm/index.d.ts.map +1 -0
  108. package/dist/core/llm/index.js +4 -0
  109. package/dist/core/llm/index.js.map +1 -0
  110. package/dist/core/llm/scripted.d.ts +16 -0
  111. package/dist/core/llm/scripted.d.ts.map +1 -0
  112. package/dist/core/llm/scripted.js +29 -0
  113. package/dist/core/llm/scripted.js.map +1 -0
  114. package/dist/core/progress.d.ts +29 -0
  115. package/dist/core/progress.d.ts.map +1 -0
  116. package/dist/core/progress.js +22 -0
  117. package/dist/core/progress.js.map +1 -0
  118. package/dist/core/registry.d.ts +29 -0
  119. package/dist/core/registry.d.ts.map +1 -0
  120. package/dist/core/registry.js +63 -0
  121. package/dist/core/registry.js.map +1 -0
  122. package/dist/core/spawn.d.ts +19 -0
  123. package/dist/core/spawn.d.ts.map +1 -0
  124. package/dist/core/spawn.js +58 -0
  125. package/dist/core/spawn.js.map +1 -0
  126. package/dist/core/state.d.ts +58 -0
  127. package/dist/core/state.d.ts.map +1 -0
  128. package/dist/core/state.js +3 -0
  129. package/dist/core/state.js.map +1 -0
  130. package/dist/core/timeout.d.ts +13 -0
  131. package/dist/core/timeout.d.ts.map +1 -0
  132. package/dist/core/timeout.js +33 -0
  133. package/dist/core/timeout.js.map +1 -0
  134. package/dist/core/types.d.ts +15 -0
  135. package/dist/core/types.d.ts.map +1 -0
  136. package/dist/core/types.js +3 -0
  137. package/dist/core/types.js.map +1 -0
  138. package/dist/core/validate.d.ts +7 -0
  139. package/dist/core/validate.d.ts.map +1 -0
  140. package/dist/core/validate.js +47 -0
  141. package/dist/core/validate.js.map +1 -0
  142. package/dist/graph.d.ts +4 -0
  143. package/dist/graph.d.ts.map +1 -0
  144. package/dist/graph.js +14 -0
  145. package/dist/graph.js.map +1 -0
  146. package/dist/index.d.ts +18 -0
  147. package/dist/index.d.ts.map +1 -0
  148. package/dist/index.js +16 -0
  149. package/dist/index.js.map +1 -0
  150. package/dist/modes/adversarial.d.ts +3 -0
  151. package/dist/modes/adversarial.d.ts.map +1 -0
  152. package/dist/modes/adversarial.js +42 -0
  153. package/dist/modes/adversarial.js.map +1 -0
  154. package/dist/modes/consensus.d.ts +3 -0
  155. package/dist/modes/consensus.d.ts.map +1 -0
  156. package/dist/modes/consensus.js +47 -0
  157. package/dist/modes/consensus.js.map +1 -0
  158. package/dist/modes/debate.d.ts +3 -0
  159. package/dist/modes/debate.d.ts.map +1 -0
  160. package/dist/modes/debate.js +76 -0
  161. package/dist/modes/debate.js.map +1 -0
  162. package/dist/modes/index.d.ts +7 -0
  163. package/dist/modes/index.d.ts.map +1 -0
  164. package/dist/modes/index.js +7 -0
  165. package/dist/modes/index.js.map +1 -0
  166. package/dist/modes/single.d.ts +3 -0
  167. package/dist/modes/single.d.ts.map +1 -0
  168. package/dist/modes/single.js +42 -0
  169. package/dist/modes/single.js.map +1 -0
  170. package/dist/modes/tournament.d.ts +3 -0
  171. package/dist/modes/tournament.d.ts.map +1 -0
  172. package/dist/modes/tournament.js +48 -0
  173. package/dist/modes/tournament.js.map +1 -0
  174. package/dist/nodes/agentRunner.d.ts +15 -0
  175. package/dist/nodes/agentRunner.d.ts.map +1 -0
  176. package/dist/nodes/agentRunner.js +106 -0
  177. package/dist/nodes/agentRunner.js.map +1 -0
  178. package/dist/nodes/auditor.d.ts +38 -0
  179. package/dist/nodes/auditor.d.ts.map +1 -0
  180. package/dist/nodes/auditor.js +179 -0
  181. package/dist/nodes/auditor.js.map +1 -0
  182. package/dist/nodes/bracket.d.ts +19 -0
  183. package/dist/nodes/bracket.d.ts.map +1 -0
  184. package/dist/nodes/bracket.js +90 -0
  185. package/dist/nodes/bracket.js.map +1 -0
  186. package/dist/nodes/consensusEngine.d.ts +18 -0
  187. package/dist/nodes/consensusEngine.d.ts.map +1 -0
  188. package/dist/nodes/consensusEngine.js +94 -0
  189. package/dist/nodes/consensusEngine.js.map +1 -0
  190. package/dist/nodes/moderator.d.ts +20 -0
  191. package/dist/nodes/moderator.d.ts.map +1 -0
  192. package/dist/nodes/moderator.js +83 -0
  193. package/dist/nodes/moderator.js.map +1 -0
  194. package/dist/nodes/planner.d.ts +17 -0
  195. package/dist/nodes/planner.d.ts.map +1 -0
  196. package/dist/nodes/planner.js +40 -0
  197. package/dist/nodes/planner.js.map +1 -0
  198. package/dist/nodes/supervisor.d.ts +28 -0
  199. package/dist/nodes/supervisor.d.ts.map +1 -0
  200. package/dist/nodes/supervisor.js +75 -0
  201. package/dist/nodes/supervisor.js.map +1 -0
  202. package/package.json +66 -0
  203. package/schemas/coterie.config.schema.json +204 -0
@@ -0,0 +1,83 @@
1
+ import { parseJsonLoose } from "../core/json.js";
2
+ const MODERATOR_SYSTEM = `You are an impartial debate moderator.
3
+ Given the latest Pro and Con arguments, produce a concise round summary and identify
4
+ the strongest unresolved disagreement. Return strict JSON only:
5
+ {
6
+ "round_summary": "<2-3 sentences>",
7
+ "unresolved": "<the strongest open disagreement>",
8
+ "fact_check_needed": ["<claim>", ...]
9
+ }`;
10
+ const DEBATE_JUDGE_SYSTEM = `You are an impartial debate judge.
11
+ You see N rounds of Pro and Con arguments on a single question. Pick the stronger
12
+ position based on: evidence quality, logical coherence, addressing the opponent's strongest points,
13
+ and practical applicability.
14
+
15
+ Return strict JSON only:
16
+ {
17
+ "winner": "pro" | "con" | "tie",
18
+ "reason": "<3-4 sentences>",
19
+ "scores": {"pro": <int 1-10>, "con": <int 1-10>}
20
+ }`;
21
+ export function makeModeratorNode(llm) {
22
+ return async (state) => {
23
+ const runs = state.runs ?? [];
24
+ const modeState = { ...(state.mode_state ?? {}) };
25
+ const proRun = [...runs].reverse().find((r) => r.role === "pro");
26
+ const conRun = [...runs].reverse().find((r) => r.role === "con");
27
+ if (!proRun || !conRun)
28
+ return { mode_state: modeState };
29
+ let summary;
30
+ if (!llm) {
31
+ summary = { round_summary: "no moderator LLM configured", unresolved: "", fact_check_needed: [] };
32
+ }
33
+ else {
34
+ const prompt = `Question: ${state.task}\n\nPro argument:\n${proRun.stdout.slice(0, 1500)}\n\n` +
35
+ `Con argument:\n${conRun.stdout.slice(0, 1500)}`;
36
+ const raw = await llm.chat(MODERATOR_SYSTEM, [{ role: "user", content: prompt }]);
37
+ summary = parseJsonLoose(raw) ?? { round_summary: raw.slice(0, 300), unresolved: "", fact_check_needed: [] };
38
+ }
39
+ modeState.rounds_completed = (modeState.rounds_completed ?? 0) + 1;
40
+ modeState.round_summaries = [...(modeState.round_summaries ?? []), summary];
41
+ return { mode_state: modeState };
42
+ };
43
+ }
44
+ export function makeDebateJudgeNode(llm) {
45
+ return async (state) => {
46
+ const cfg = state.config;
47
+ const sides = (cfg.debate?.sides ?? []);
48
+ const runs = state.runs ?? [];
49
+ const proRuns = runs.filter((r) => r.role === "pro");
50
+ const conRuns = runs.filter((r) => r.role === "con");
51
+ // Pair by the longer side so a dropped/failed round on either side isn't
52
+ // silently omitted from the judged transcript.
53
+ const rounds = Math.max(proRuns.length, conRuns.length);
54
+ const transcript = Array.from({ length: rounds }, (_, i) => {
55
+ const pro = proRuns[i];
56
+ const con = conRuns[i];
57
+ return `Round ${i + 1}\nPRO: ${pro ? pro.stdout.slice(0, 800) : "(missing)"}\nCON: ${con ? con.stdout.slice(0, 800) : "(missing)"}`;
58
+ }).join("\n\n");
59
+ let decision;
60
+ if (!llm) {
61
+ decision = { winner: "tie", reason: "no judge LLM configured", scores: {} };
62
+ }
63
+ else {
64
+ const raw = await llm.chat(DEBATE_JUDGE_SYSTEM, [
65
+ { role: "user", content: `Question: ${state.task}\n\n${transcript}` },
66
+ ]);
67
+ decision = parseJsonLoose(raw) ?? { winner: "tie", reason: `judge output unparseable: ${raw.slice(0, 120)}`, scores: {} };
68
+ }
69
+ const winnerLabel = decision.winner ?? "tie";
70
+ const winnerAgent = winnerLabel === "pro" ? sides[0] : winnerLabel === "con" ? sides[1] : "tie";
71
+ return {
72
+ mode_state: { ...(state.mode_state ?? {}), debate_verdict: decision },
73
+ judge_history: [{
74
+ step: state.current_step_idx ?? 0,
75
+ winner: winnerAgent,
76
+ reason: decision.reason ?? "",
77
+ scores: decision.scores ?? {},
78
+ }],
79
+ status: "done",
80
+ };
81
+ };
82
+ }
83
+ //# sourceMappingURL=moderator.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"moderator.js","sourceRoot":"","sources":["../../src/nodes/moderator.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,17 @@
1
+ import type { LLMClient } from "../core/llm/base.js";
2
+ import type { CoterieState } from "../core/state.js";
3
+ export declare function makePlannerNode(): (state: CoterieState) => Promise<{
4
+ plan: string[];
5
+ current_step_idx: number;
6
+ status: "executing";
7
+ mode_state: Record<string, any>;
8
+ }>;
9
+ export declare function makeLLMPlannerNode(llm: LLMClient, opts?: {
10
+ maxSubtasks?: number;
11
+ }): (state: CoterieState) => Promise<{
12
+ plan: string[];
13
+ current_step_idx: number;
14
+ status: "executing";
15
+ mode_state: Record<string, any>;
16
+ }>;
17
+ //# sourceMappingURL=planner.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"planner.d.ts","sourceRoot":"","sources":["../../src/nodes/planner.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,qBAAqB,CAAC;AACrD,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,kBAAkB,CAAC;AAErD,wBAAgB,eAAe,KACf,OAAO,YAAY;;;;;GAMlC;AASD,wBAAgB,kBAAkB,CAAC,GAAG,EAAE,SAAS,EAAE,IAAI,GAAE;IAAE,WAAW,CAAC,EAAE,MAAM,CAAA;CAAO,IAEtE,OAAO,YAAY;;;;;GAoBlC"}
@@ -0,0 +1,40 @@
1
+ export function makePlannerNode() {
2
+ return async (state) => ({
3
+ plan: [state.task],
4
+ current_step_idx: 0,
5
+ status: "executing",
6
+ mode_state: state.mode_state ?? {},
7
+ });
8
+ }
9
+ const PLANNER_SYSTEM = `You decompose a coding task into a sequence of focused subtasks.
10
+ Keep subtasks atomic, in execution order, and roughly 1-2 sentences each.
11
+ Aim for 1-5 subtasks total — return exactly one when the task is already atomic.
12
+
13
+ Return strict JSON only — no prose, no markdown:
14
+ {"subtasks": ["<subtask 1>", "<subtask 2>", ...]}`;
15
+ export function makeLLMPlannerNode(llm, opts = {}) {
16
+ const maxSubtasks = opts.maxSubtasks ?? 5;
17
+ return async (state) => {
18
+ const raw = await llm.chat(PLANNER_SYSTEM, [{ role: "user", content: state.task }]);
19
+ let subtasks;
20
+ try {
21
+ const payload = JSON.parse(raw);
22
+ if (!Array.isArray(payload.subtasks) || !payload.subtasks.every((s) => typeof s === "string")) {
23
+ throw new Error("invalid subtasks");
24
+ }
25
+ subtasks = payload.subtasks.slice(0, maxSubtasks);
26
+ if (subtasks.length === 0)
27
+ subtasks = [state.task];
28
+ }
29
+ catch {
30
+ subtasks = [state.task];
31
+ }
32
+ return {
33
+ plan: subtasks,
34
+ current_step_idx: 0,
35
+ status: "executing",
36
+ mode_state: state.mode_state ?? {},
37
+ };
38
+ };
39
+ }
40
+ //# sourceMappingURL=planner.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"planner.js","sourceRoot":"","sources":["../../src/nodes/planner.ts"],"names":[],"mappings":"AAGA,MAAM,UAAU,eAAe;IAC7B,OAAO,KAAK,EAAE,KAAmB,EAAE,EAAE,CAAC,CAAC;QACrC,IAAI,EAAE,CAAC,KAAK,CAAC,IAAI,CAAC;QAClB,gBAAgB,EAAE,CAAC;QACnB,MAAM,EAAE,WAAoB;QAC5B,UAAU,EAAE,KAAK,CAAC,UAAU,IAAI,EAAE;KACnC,CAAC,CAAC;AACL,CAAC;AAED,MAAM,cAAc,GAAG;;;;;kDAK2B,CAAC;AAEnD,MAAM,UAAU,kBAAkB,CAAC,GAAc,EAAE,OAAiC,EAAE;IACpF,MAAM,WAAW,GAAG,IAAI,CAAC,WAAW,IAAI,CAAC,CAAC;IAC1C,OAAO,KAAK,EAAE,KAAmB,EAAE,EAAE;QACnC,MAAM,GAAG,GAAG,MAAM,GAAG,CAAC,IAAI,CAAC,cAAc,EAAE,CAAC,EAAE,IAAI,EAAE,MAAM,EAAE,OAAO,EAAE,KAAK,CAAC,IAAI,EAAE,CAAC,CAAC,CAAC;QACpF,IAAI,QAAkB,CAAC;QACvB,IAAI,CAAC;YACH,MAAM,OAAO,GAAG,IAAI,CAAC,KAAK,CAAC,GAAG,CAA2B,CAAC;YAC1D,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,OAAO,CAAC,QAAQ,CAAC,IAAI,CAAC,OAAO,CAAC,QAAQ,CAAC,KAAK,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,OAAO,CAAC,KAAK,QAAQ,CAAC,EAAE,CAAC;gBAC9F,MAAM,IAAI,KAAK,CAAC,kBAAkB,CAAC,CAAC;YACtC,CAAC;YACD,QAAQ,GAAG,OAAO,CAAC,QAAQ,CAAC,KAAK,CAAC,CAAC,EAAE,WAAW,CAAC,CAAC;YAClD,IAAI,QAAQ,CAAC,MAAM,KAAK,CAAC;gBAAE,QAAQ,GAAG,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC;QACrD,CAAC;QAAC,MAAM,CAAC;YACP,QAAQ,GAAG,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC;QAC1B,CAAC;QACD,OAAO;YACL,IAAI,EAAE,QAAQ;YACd,gBAAgB,EAAE,CAAC;YACnB,MAAM,EAAE,WAAoB;YAC5B,UAAU,EAAE,KAAK,CAAC,UAAU,IAAI,EAAE;SACnC,CAAC;IACJ,CAAC,CAAC;AACJ,CAAC"}
@@ -0,0 +1,28 @@
1
+ import type { LLMClient } from "../core/llm/base.js";
2
+ import type { CoterieState } from "../core/state.js";
3
+ export declare function makeSupervisorNode(llm: LLMClient | null): (state: CoterieState) => Promise<{
4
+ status?: undefined;
5
+ next_agent?: undefined;
6
+ route_history?: undefined;
7
+ } | {
8
+ status: "done";
9
+ next_agent: null;
10
+ route_history?: undefined;
11
+ } | {
12
+ next_agent: any;
13
+ route_history: {
14
+ step: number;
15
+ agent_id: any;
16
+ reason: string;
17
+ strategy: string;
18
+ }[];
19
+ status: "executing";
20
+ }>;
21
+ export declare function makeStepAdvanceNode(): (state: CoterieState) => Promise<{
22
+ current_step_idx?: undefined;
23
+ status?: undefined;
24
+ } | {
25
+ current_step_idx: number;
26
+ status: "routing";
27
+ }>;
28
+ //# sourceMappingURL=supervisor.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"supervisor.d.ts","sourceRoot":"","sources":["../../src/nodes/supervisor.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,qBAAqB,CAAC;AACrD,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,kBAAkB,CAAC;AAcrD,wBAAgB,kBAAkB,CAAC,GAAG,EAAE,SAAS,GAAG,IAAI,IACxC,OAAO,YAAY;;;;;;;;;;;;;;;;;GAsDlC;AAED,wBAAgB,mBAAmB,KACnB,OAAO,YAAY;;;;;;GAIlC"}
@@ -0,0 +1,75 @@
1
+ import { parseJsonLoose } from "../core/json.js";
2
+ const SUPERVISOR_SYSTEM = `You route coding subtasks to specialist CLI agents.
3
+ Pick the best agent for the given subtask based on each agent's stated strengths.
4
+ Be decisive. Return strict JSON only — no prose, no markdown.
5
+
6
+ Output schema: {"agent_id": "<one of the provided agent ids>", "reason": "<one sentence>"}`;
7
+ function formatAgents(agents) {
8
+ return agents
9
+ .map((a) => `- ${a.id} (adapter=${a.adapter}, strengths=${JSON.stringify(a.strengths ?? [])})`)
10
+ .join("\n");
11
+ }
12
+ export function makeSupervisorNode(llm) {
13
+ return async (state) => {
14
+ if (state.status === "failed" || state.status === "awaiting_human")
15
+ return {};
16
+ const plan = state.plan ?? [];
17
+ const idx = state.current_step_idx ?? 0;
18
+ if (idx >= plan.length) {
19
+ return { status: "done", next_agent: null };
20
+ }
21
+ const cfg = state.config;
22
+ const agents = cfg.agents;
23
+ if (!agents?.length) {
24
+ throw new Error("supervisor: config has no agents to route to");
25
+ }
26
+ const subtask = plan[idx];
27
+ const routerCfg = cfg.router ?? {};
28
+ const strategy = routerCfg.strategy ?? "llm";
29
+ const enabled = routerCfg.enabled !== false;
30
+ // round-robin (and disabled) are deterministic. 'manual' has no interactive
31
+ // selection channel in a headless run, so it falls back to round-robin
32
+ // deterministically rather than throwing or silently hitting the LLM path.
33
+ if (!enabled || strategy === "round-robin" || strategy === "manual") {
34
+ const chosen = agents[idx % agents.length];
35
+ const why = !enabled ? "disabled" : strategy === "manual" ? "manual→round-robin" : "round-robin";
36
+ return {
37
+ next_agent: chosen.id,
38
+ route_history: [{ step: idx, agent_id: chosen.id, reason: why, strategy: why }],
39
+ status: "executing",
40
+ };
41
+ }
42
+ if (!llm)
43
+ throw new Error("supervisor with strategy='llm' requires an LLMClient");
44
+ const prompt = `Task: ${state.task}\nSubtask: ${subtask}\n\nAvailable agents:\n${formatAgents(agents)}`;
45
+ const raw = await llm.chat(SUPERVISOR_SYSTEM, [{ role: "user", content: prompt }]);
46
+ const decision = parseJsonLoose(raw);
47
+ let agentId;
48
+ let reason;
49
+ if (decision && typeof decision.agent_id === "string") {
50
+ agentId = decision.agent_id;
51
+ reason = decision.reason ?? "";
52
+ }
53
+ else {
54
+ agentId = agents[0].id;
55
+ reason = `router output unparseable: ${raw.slice(0, 120)}`;
56
+ }
57
+ if (!agents.find((a) => a.id === agentId)) {
58
+ agentId = agents[0].id;
59
+ reason = `router picked unknown agent; fell back to ${agentId}`;
60
+ }
61
+ return {
62
+ next_agent: agentId,
63
+ route_history: [{ step: idx, agent_id: agentId, reason, strategy: "llm" }],
64
+ status: "executing",
65
+ };
66
+ };
67
+ }
68
+ export function makeStepAdvanceNode() {
69
+ return async (state) => {
70
+ if (state.status === "failed" || state.status === "awaiting_human")
71
+ return {};
72
+ return { current_step_idx: (state.current_step_idx ?? 0) + 1, status: "routing" };
73
+ };
74
+ }
75
+ //# sourceMappingURL=supervisor.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"supervisor.js","sourceRoot":"","sources":["../../src/nodes/supervisor.ts"],"names":[],"mappings":"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"}
package/package.json ADDED
@@ -0,0 +1,66 @@
1
+ {
2
+ "name": "coterie",
3
+ "version": "0.1.0",
4
+ "description": "Conversational meta-agent for your terminal: every prompt runs through a multi-agent coordination round (debate, adversarial, tournament, consensus) over Claude Code + Codex, on your subscriptions.",
5
+ "license": "MIT",
6
+ "author": "Chris King <chris@cking.me>",
7
+ "homepage": "https://coterie.dev",
8
+ "repository": {
9
+ "type": "git",
10
+ "url": "git+https://github.com/cxk280/coterie.git",
11
+ "directory": "packages/coterie-js"
12
+ },
13
+ "bugs": "https://github.com/cxk280/coterie/issues",
14
+ "keywords": [
15
+ "langgraph",
16
+ "agents",
17
+ "llm",
18
+ "orchestration",
19
+ "claude",
20
+ "codex",
21
+ "cursor"
22
+ ],
23
+ "type": "module",
24
+ "main": "./dist/index.js",
25
+ "types": "./dist/index.d.ts",
26
+ "exports": {
27
+ ".": {
28
+ "types": "./dist/index.d.ts",
29
+ "import": "./dist/index.js"
30
+ }
31
+ },
32
+ "bin": {
33
+ "coterie": "dist/cli.js"
34
+ },
35
+ "files": [
36
+ "dist",
37
+ "schemas",
38
+ "README.md",
39
+ "LICENSE"
40
+ ],
41
+ "scripts": {
42
+ "build": "tsc -p tsconfig.json",
43
+ "test": "vitest run",
44
+ "test:watch": "vitest",
45
+ "test:e2e": "vitest run --config vitest.e2e.config.ts",
46
+ "lint": "eslint src",
47
+ "dev": "tsx src/cli.ts",
48
+ "prepublishOnly": "npm run build"
49
+ },
50
+ "engines": {
51
+ "node": ">=20"
52
+ },
53
+ "dependencies": {
54
+ "@langchain/langgraph": "^0.2.0",
55
+ "ajv": "^8.17.1",
56
+ "commander": "^12.1.0",
57
+ "yaml": "^2.5.0",
58
+ "kleur": "^4.1.5"
59
+ },
60
+ "devDependencies": {
61
+ "@types/node": "^20.14.0",
62
+ "tsx": "^4.16.0",
63
+ "typescript": "^5.5.0",
64
+ "vitest": "^2.0.0"
65
+ }
66
+ }
@@ -0,0 +1,204 @@
1
+ {
2
+ "$schema": "https://json-schema.org/draft/2020-12/schema",
3
+ "$id": "https://coterie.dev/schemas/coterie.config.schema.json",
4
+ "title": "Coterie configuration",
5
+ "description": "Single source of truth for Coterie runtime configuration. The Python and JS runtimes both validate against this schema.",
6
+ "type": "object",
7
+ "required": ["mode", "agents"],
8
+ "additionalProperties": false,
9
+ "properties": {
10
+ "version": {"type": "integer", "const": 1},
11
+ "mode": {
12
+ "type": "string",
13
+ "enum": ["single", "consensus", "adversarial", "debate", "tournament"],
14
+ "description": "Coordination pattern. Each mode wires a different LangGraph topology. See docs/modes.md."
15
+ },
16
+ "agents": {
17
+ "type": "array",
18
+ "minItems": 1,
19
+ "items": {
20
+ "type": "object",
21
+ "required": ["id", "adapter"],
22
+ "additionalProperties": false,
23
+ "properties": {
24
+ "id": {"type": "string", "pattern": "^[a-z0-9][a-z0-9-]*$"},
25
+ "adapter": {
26
+ "type": "string",
27
+ "enum": ["claude-code", "codex", "cursor", "fake"]
28
+ },
29
+ "command": {"type": "array", "items": {"type": "string"}},
30
+ "model": {"type": "string"},
31
+ "strengths": {"type": "array", "items": {"type": "string"}},
32
+ "timeout_s": {"type": "integer", "minimum": 10, "default": 600}
33
+ }
34
+ }
35
+ },
36
+ "router": {
37
+ "type": "object",
38
+ "additionalProperties": false,
39
+ "description": "Used in `single` mode to pick which agent handles each subtask.",
40
+ "properties": {
41
+ "enabled": {"type": "boolean", "default": true},
42
+ "model": {"type": "string", "default": "claude-haiku-4-5-20251001"},
43
+ "strategy": {
44
+ "type": "string",
45
+ "enum": ["llm", "round-robin", "manual"],
46
+ "default": "llm"
47
+ }
48
+ }
49
+ },
50
+ "planner": {
51
+ "type": "object",
52
+ "additionalProperties": false,
53
+ "description": "LLM-driven task decomposition. Off by default (trivial planner: plan = [task]). When enabled, decomposes the task into a sequence of subtasks. Only `single` mode iterates multi-step plans today; other modes use plan[0].",
54
+ "properties": {
55
+ "enabled": {"type": "boolean", "default": false},
56
+ "model": {"type": "string", "default": "claude-haiku-4-5-20251001"},
57
+ "max_subtasks": {"type": "integer", "minimum": 1, "default": 5}
58
+ }
59
+ },
60
+ "executor": {
61
+ "type": "object",
62
+ "additionalProperties": false,
63
+ "description": "Adapter execution strategy. Default: `local` for sequential modes (single, adversarial, debate), `isolated` for parallel modes (consensus, tournament). Override here if needed.",
64
+ "properties": {
65
+ "kind": {
66
+ "type": "string",
67
+ "enum": ["local", "isolated"],
68
+ "description": "`local`: shared workdir across all calls. `isolated`: each call gets an ephemeral git worktree (or tempdir fallback)."
69
+ }
70
+ }
71
+ },
72
+ "single": {
73
+ "type": "object",
74
+ "additionalProperties": false,
75
+ "description": "Single-routed mode: router picks one agent per subtask."
76
+ },
77
+ "consensus": {
78
+ "type": "object",
79
+ "additionalProperties": false,
80
+ "properties": {
81
+ "participants": {
82
+ "type": "array",
83
+ "items": {"type": "string"},
84
+ "minItems": 2
85
+ },
86
+ "threshold": {
87
+ "type": "number",
88
+ "minimum": 0,
89
+ "maximum": 1,
90
+ "default": 0.5,
91
+ "description": "Agreement ratio at which a clustered finding is 'confirmed'."
92
+ },
93
+ "max_rounds": {"type": "integer", "minimum": 1, "default": 1},
94
+ "engine": {
95
+ "type": "object",
96
+ "additionalProperties": false,
97
+ "properties": {
98
+ "model": {"type": "string", "default": "claude-opus-4-7"},
99
+ "confirm_threshold": {
100
+ "type": "number",
101
+ "minimum": 0,
102
+ "maximum": 1,
103
+ "default": 0.5
104
+ }
105
+ }
106
+ }
107
+ }
108
+ },
109
+ "adversarial": {
110
+ "type": "object",
111
+ "additionalProperties": false,
112
+ "required": ["implementer", "auditor"],
113
+ "properties": {
114
+ "implementer": {"type": "string"},
115
+ "auditor": {"type": "string"},
116
+ "judge": {
117
+ "type": "object",
118
+ "additionalProperties": false,
119
+ "properties": {
120
+ "model": {"type": "string", "default": "claude-opus-4-7"},
121
+ "sustain_threshold": {
122
+ "type": "string",
123
+ "enum": ["low", "medium", "high"],
124
+ "default": "medium"
125
+ }
126
+ }
127
+ },
128
+ "max_rounds": {"type": "integer", "minimum": 1, "default": 3}
129
+ }
130
+ },
131
+ "debate": {
132
+ "type": "object",
133
+ "additionalProperties": false,
134
+ "required": ["sides"],
135
+ "properties": {
136
+ "sides": {
137
+ "type": "array",
138
+ "minItems": 2,
139
+ "maxItems": 2,
140
+ "items": {"type": "string"}
141
+ },
142
+ "rounds": {"type": "integer", "minimum": 1, "default": 3},
143
+ "moderator": {
144
+ "type": "object",
145
+ "additionalProperties": false,
146
+ "properties": {
147
+ "model": {"type": "string", "default": "claude-haiku-4-5-20251001"}
148
+ }
149
+ },
150
+ "judge": {
151
+ "type": "object",
152
+ "additionalProperties": false,
153
+ "properties": {
154
+ "model": {"type": "string", "default": "claude-opus-4-7"}
155
+ }
156
+ }
157
+ }
158
+ },
159
+ "tournament": {
160
+ "type": "object",
161
+ "additionalProperties": false,
162
+ "required": ["participants"],
163
+ "properties": {
164
+ "participants": {
165
+ "type": "array",
166
+ "minItems": 2,
167
+ "items": {"type": "string"}
168
+ },
169
+ "rounds": {
170
+ "type": "integer",
171
+ "minimum": 1,
172
+ "default": 1,
173
+ "description": "Number of elimination rounds. 1 = single N-way ranking (default). N>1 = bracket: each round halves the field via the judge until one survivor or N rounds completed."
174
+ },
175
+ "judge": {
176
+ "type": "object",
177
+ "additionalProperties": false,
178
+ "properties": {
179
+ "model": {"type": "string", "default": "claude-opus-4-7"},
180
+ "criteria": {
181
+ "type": "array",
182
+ "items": {"type": "string"},
183
+ "default": ["correctness", "minimal-diff", "tests-pass", "clarity"]
184
+ }
185
+ }
186
+ }
187
+ }
188
+ },
189
+ "budget": {
190
+ "type": "object",
191
+ "additionalProperties": false,
192
+ "properties": {
193
+ "max_usd_per_task": {"type": "number", "minimum": 0},
194
+ "warn_at_usd": {"type": "number", "minimum": 0},
195
+ "on_exceed": {
196
+ "type": "string",
197
+ "enum": ["halt", "warn", "checkpoint"],
198
+ "default": "checkpoint"
199
+ }
200
+ }
201
+ },
202
+ "workdir": {"type": "string", "default": "."}
203
+ }
204
+ }