palabre 0.8.0 → 0.9.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.
@@ -1,6 +1,7 @@
1
1
  import { createAgent } from "./adapters/index.js";
2
2
  import { AdapterError } from "./errors.js";
3
3
  import { createTranslator } from "./i18n.js";
4
+ import { OllamaUrlError } from "./ollamaUrl.js";
4
5
  export const MAX_ASK_AGENTS = 4;
5
6
  /**
6
7
  * Point d'entrée de l'orchestration.
@@ -27,8 +28,8 @@ export async function runDebate(config, options, renderer, messages = createTran
27
28
  { name: options.agentB, role: agentBConfig.role, type: agentBConfig.type }
28
29
  ]);
29
30
  const agents = [
30
- createAgent(options.agentA, agentAConfig),
31
- createAgent(options.agentB, agentBConfig)
31
+ createAgent(options.agentA, agentAConfig, { ollamaUrl: options.ollamaUrl }),
32
+ createAgent(options.agentB, agentBConfig, { ollamaUrl: options.ollamaUrl })
32
33
  ];
33
34
  const transcript = [];
34
35
  let stopReason;
@@ -73,7 +74,7 @@ export async function runDebate(config, options, renderer, messages = createTran
73
74
  agent: current.name,
74
75
  role: current.role,
75
76
  turn
76
- });
77
+ }, messages);
77
78
  renderer?.error(failure);
78
79
  return {
79
80
  options,
@@ -106,6 +107,7 @@ export async function runDebate(config, options, renderer, messages = createTran
106
107
  const cancellation = cancellationFailureIfAborted(options, messages, {
107
108
  phase: "summary",
108
109
  agent: resolveSummaryAgentName(options),
110
+ role: summaryRole(),
109
111
  turn: transcript.length + 1
110
112
  });
111
113
  if (cancellation) {
@@ -123,8 +125,9 @@ export async function runDebate(config, options, renderer, messages = createTran
123
125
  failure = toDebateFailure(error, {
124
126
  phase: "summary",
125
127
  agent: resolveSummaryAgentName(options),
128
+ role: summaryRole(),
126
129
  turn: transcript.length + 1
127
- });
130
+ }, messages);
128
131
  renderer?.error(failure);
129
132
  }
130
133
  }
@@ -161,7 +164,7 @@ export async function runAsk(config, options, renderer, messages = createTransla
161
164
  role: agentConfig.role,
162
165
  type: agentConfig.type
163
166
  })));
164
- const agents = agentEntries.map(([name, agentConfig]) => createAgent(name, agentConfig));
167
+ const agents = agentEntries.map(([name, agentConfig]) => createAgent(name, agentConfig, { ollamaUrl: options.ollamaUrl }));
165
168
  const transcript = [];
166
169
  for (let index = 0; index < agents.length; index += 1) {
167
170
  const current = agents[index];
@@ -210,7 +213,7 @@ export async function runAsk(config, options, renderer, messages = createTransla
210
213
  agent: current.name,
211
214
  role: current.role,
212
215
  turn: response
213
- });
216
+ }, messages);
214
217
  renderer?.error(failure);
215
218
  return {
216
219
  options,
@@ -243,6 +246,7 @@ export async function runAsk(config, options, renderer, messages = createTransla
243
246
  const cancellation = cancellationFailureIfAborted(options, messages, {
244
247
  phase: "summary",
245
248
  agent: summaryAgentName,
249
+ role: summaryRole(),
246
250
  turn: transcript.length + 1
247
251
  });
248
252
  if (cancellation) {
@@ -259,8 +263,9 @@ export async function runAsk(config, options, renderer, messages = createTransla
259
263
  failure = toDebateFailure(error, {
260
264
  phase: "summary",
261
265
  agent: resolveSummaryAgentName(options),
266
+ role: summaryRole(),
262
267
  turn: transcript.length + 1
263
- });
268
+ }, messages);
264
269
  renderer?.error(failure);
265
270
  }
266
271
  }
@@ -331,16 +336,17 @@ async function generateSummary(config, options, transcript, renderer, messages =
331
336
  if (!summaryConfig) {
332
337
  throw new Error(messages.orchestrator.unknownSummaryAgent(summaryAgentName));
333
338
  }
334
- const summaryAgent = createAgent(summaryAgentName, summaryConfig);
335
- renderer?.summaryStart(summaryAgent.name, summaryAgent.role);
336
- renderer?.thinkingStart(summaryAgent.name, summaryAgent.role);
339
+ const summaryAgent = createAgent(summaryAgentName, summaryConfig, { ollamaUrl: options.ollamaUrl });
340
+ const role = summaryRole();
341
+ renderer?.summaryStart(summaryAgent.name, role);
342
+ renderer?.thinkingStart(summaryAgent.name, role);
337
343
  const response = await summaryAgent.generate({
338
344
  topic: options.topic,
339
345
  turn: transcript.length + 1,
340
346
  totalTurns: options.mode === "ask" ? transcript.length : options.turns,
341
347
  selfName: summaryAgent.name,
342
348
  peerName: options.mode === "ask" ? "ask-responses" : "transcript",
343
- selfRole: summaryAgent.role,
349
+ selfRole: role,
344
350
  mode: "summary",
345
351
  language: options.language,
346
352
  session: options.session,
@@ -350,13 +356,16 @@ async function generateSummary(config, options, transcript, renderer, messages =
350
356
  }).finally(() => renderer?.thinkingEnd());
351
357
  const summary = {
352
358
  agent: summaryAgent.name,
353
- role: summaryAgent.role,
359
+ role,
354
360
  content: response.content,
355
361
  createdAt: new Date().toISOString()
356
362
  };
357
363
  renderer?.message(summary.content);
358
364
  return summary;
359
365
  }
366
+ function summaryRole() {
367
+ return "summarizer";
368
+ }
360
369
  function cancellationFailureIfAborted(options, messages, context) {
361
370
  if (!options.signal?.aborted) {
362
371
  return undefined;
@@ -385,7 +394,7 @@ function resolveSummaryAgentName(options) {
385
394
  }
386
395
  return options.agentB;
387
396
  }
388
- function toDebateFailure(error, context) {
397
+ function toDebateFailure(error, context, messages) {
389
398
  if (error instanceof AdapterError) {
390
399
  return {
391
400
  phase: context.phase,
@@ -397,6 +406,18 @@ function toDebateFailure(error, context) {
397
406
  details: error.details
398
407
  };
399
408
  }
409
+ if (error instanceof OllamaUrlError) {
410
+ const message = error.kind === "empty"
411
+ ? messages.common.ollamaUrlEmpty
412
+ : error.kind === "protocol"
413
+ ? messages.common.ollamaUrlProtocol(error.protocol ?? "")
414
+ : messages.common.ollamaUrlInvalid(error.value);
415
+ return {
416
+ ...context,
417
+ kind: "unknown",
418
+ message
419
+ };
420
+ }
400
421
  return {
401
422
  phase: context.phase,
402
423
  agent: context.agent,
package/dist/presets.js CHANGED
@@ -1,4 +1,4 @@
1
- import { detectionForCommand } from "./agentRegistry.js";
1
+ import { detectionForCommand, isRetiredAgentName } from "./agentRegistry.js";
2
2
  const presets = {
3
3
  "codex-claude": {
4
4
  agentA: "codex",
@@ -56,30 +56,6 @@ const presets = {
56
56
  agentA: "antigravity",
57
57
  agentB: "claude"
58
58
  },
59
- "gemini-opencode": {
60
- agentA: "gemini",
61
- agentB: "opencode"
62
- },
63
- "opencode-gemini": {
64
- agentA: "opencode",
65
- agentB: "gemini"
66
- },
67
- "gemini-vibe": {
68
- agentA: "gemini",
69
- agentB: "vibe"
70
- },
71
- "vibe-gemini": {
72
- agentA: "vibe",
73
- agentB: "gemini"
74
- },
75
- "gemini-antigravity": {
76
- agentA: "gemini",
77
- agentB: "antigravity"
78
- },
79
- "antigravity-gemini": {
80
- agentA: "antigravity",
81
- agentB: "gemini"
82
- },
83
59
  "opencode-antigravity": {
84
60
  agentA: "opencode",
85
61
  agentB: "antigravity"
@@ -136,14 +112,6 @@ const presets = {
136
112
  agentA: "ollama-local",
137
113
  agentB: "claude"
138
114
  },
139
- "gemini-ollama": {
140
- agentA: "gemini",
141
- agentB: "ollama-local"
142
- },
143
- "ollama-gemini": {
144
- agentA: "ollama-local",
145
- agentB: "gemini"
146
- },
147
115
  "antigravity-ollama": {
148
116
  agentA: "antigravity",
149
117
  agentB: "ollama-local"
@@ -151,22 +119,6 @@ const presets = {
151
119
  "ollama-antigravity": {
152
120
  agentA: "ollama-local",
153
121
  agentB: "antigravity"
154
- },
155
- "codex-gemini": {
156
- agentA: "codex",
157
- agentB: "gemini"
158
- },
159
- "gemini-codex": {
160
- agentA: "gemini",
161
- agentB: "codex"
162
- },
163
- "claude-gemini": {
164
- agentA: "claude",
165
- agentB: "gemini"
166
- },
167
- "gemini-claude": {
168
- agentA: "gemini",
169
- agentB: "claude"
170
122
  }
171
123
  };
172
124
  /** Retourne la paire d'agents pour `name`. Lève une erreur avec la liste des presets disponibles si inconnu. */
@@ -209,6 +161,26 @@ export function listPresetsWithAvailability(config, discovery, messages) {
209
161
  };
210
162
  });
211
163
  }
164
+ /**
165
+ * Retourne tous les agents de la config avec la même disponibilité que celle
166
+ * utilisée pour les presets. Les intégrations ne doivent pas réimplémenter la
167
+ * découverte des commandes ou des modèles Ollama.
168
+ */
169
+ export function listAgentsWithAvailability(config, discovery, messages) {
170
+ return Object.entries(config.agents)
171
+ .filter(([name]) => !isRetiredAgentName(name))
172
+ .sort(([left], [right]) => left.localeCompare(right))
173
+ .map(([name, agentConfig]) => {
174
+ const check = checkAgentAvailability(name, config, discovery, messages);
175
+ return {
176
+ name,
177
+ type: agentConfig.type,
178
+ role: agentConfig.role,
179
+ available: check.available,
180
+ ...(check.available ? {} : { unavailableReason: check.reason })
181
+ };
182
+ });
183
+ }
212
184
  /** Recherche inverse : retourne le nom du preset correspondant à une paire `(agentA, agentB)`, ou `undefined`. */
213
185
  export function findPresetNameForPair(agentA, agentB) {
214
186
  return Object.entries(presets).find(([, preset]) => preset.agentA === agentA && preset.agentB === agentB)?.[0];
@@ -219,12 +191,13 @@ function checkAgentAvailability(agentName, config, discovery, messages) {
219
191
  return unavailable(agentName, messages?.presets.missingAgent(agentName) ?? `agent absent de la config: ${agentName}`);
220
192
  }
221
193
  if (agent.type === "ollama") {
222
- if (!discovery.ollama.available) {
223
- return unavailable(agentName, discovery.ollama.commandAvailable
194
+ const ollama = discovery.ollamaAgents?.[agentName] ?? discovery.ollama;
195
+ if (!ollama.available) {
196
+ return unavailable(agentName, ollama.commandAvailable
224
197
  ? messages?.presets.ollamaUnreachable(agentName) ?? `Ollama non joignable pour ${agentName}`
225
198
  : messages?.presets.ollamaNotDetected(agentName) ?? `Ollama non détecté pour ${agentName}`);
226
199
  }
227
- if (!discovery.ollama.models.includes(agent.model)) {
200
+ if (!ollama.models.includes(agent.model)) {
228
201
  return unavailable(agentName, messages?.presets.missingOllamaModel(agentName, agent.model) ?? `modèle Ollama absent pour ${agentName}: ${agent.model}`);
229
202
  }
230
203
  return available(agentName);