palabre 0.8.1 → 0.9.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +2 -0
- package/dist/adapters/index.js +2 -2
- package/dist/adapters/ollama.js +8 -6
- package/dist/agentRegistry.js +6 -0
- package/dist/args.js +1 -0
- package/dist/commands/agents.js +85 -0
- package/dist/commands/context.js +25 -0
- package/dist/commands/history.js +28 -0
- package/dist/commands/init.js +59 -0
- package/dist/commands/presets.js +34 -0
- package/dist/commands/shared.js +4 -0
- package/dist/commands/update.js +21 -0
- package/dist/config.js +8 -0
- package/dist/discovery.js +36 -6
- package/dist/doctor.js +19 -4
- package/dist/index.js +66 -732
- package/dist/limits.js +1 -0
- package/dist/messages/common.js +6 -0
- package/dist/messages/doctor.js +2 -2
- package/dist/messages/help.js +6 -0
- package/dist/messages/tui.js +14 -0
- package/dist/ollamaUrl.js +76 -0
- package/dist/orchestrator.js +29 -24
- package/dist/output.js +1 -10
- package/dist/presets.js +25 -4
- package/dist/renderers/console.js +1 -7
- package/dist/renderers/ndjson.js +1 -10
- package/dist/renderers/tui.js +50 -17
- package/dist/runOptions.js +66 -0
- package/dist/tuiController.js +400 -0
- package/dist/tuiState.js +1 -0
- package/package.json +3 -2
package/dist/limits.js
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { createTranslator } from "./i18n.js";
|
|
2
2
|
export const DEFAULT_TURNS = 4;
|
|
3
|
+
export const MAX_ASK_AGENTS = 4;
|
|
3
4
|
export const MAX_TURNS = 20;
|
|
4
5
|
/** Convertit `value` en nombre et valide la plage [1, `MAX_TURNS`]. Lève une erreur si invalide. */
|
|
5
6
|
export function parseTurns(value, label = "--turns", messages = createTranslator("fr")) {
|
package/dist/messages/common.js
CHANGED
|
@@ -15,6 +15,9 @@ export const commonMessages = {
|
|
|
15
15
|
configInvalidShape: (configPath) => `Config invalide: ${configPath} ne contient pas un objet JSON. Relance palabre init ou corrige le fichier.`,
|
|
16
16
|
configMissingAgents: (configPath) => `Config invalide: ${configPath} ne déclare pas de bloc "agents". Relance palabre init ou ajoute au moins un agent.`,
|
|
17
17
|
configEmptyAgents: (configPath) => `Config invalide: ${configPath} ne déclare aucun agent. Ajoute au moins un agent ou relance palabre init.`,
|
|
18
|
+
ollamaUrlEmpty: "L'adresse Ollama ne peut pas être vide.",
|
|
19
|
+
ollamaUrlInvalid: (value) => `Adresse Ollama invalide: ${value}.`,
|
|
20
|
+
ollamaUrlProtocol: (protocol) => `Protocole Ollama invalide: ${protocol}. Utilise http: ou https:.`,
|
|
18
21
|
errorPrefix: "Erreur"
|
|
19
22
|
},
|
|
20
23
|
en: {
|
|
@@ -33,6 +36,9 @@ export const commonMessages = {
|
|
|
33
36
|
configInvalidShape: (configPath) => `Invalid config: ${configPath} does not contain a JSON object. Run palabre init or fix the file.`,
|
|
34
37
|
configMissingAgents: (configPath) => `Invalid config: ${configPath} has no "agents" block. Run palabre init or add at least one agent.`,
|
|
35
38
|
configEmptyAgents: (configPath) => `Invalid config: ${configPath} declares no agent. Add at least one agent or run palabre init.`,
|
|
39
|
+
ollamaUrlEmpty: "The Ollama address cannot be empty.",
|
|
40
|
+
ollamaUrlInvalid: (value) => `Invalid Ollama address: ${value}.`,
|
|
41
|
+
ollamaUrlProtocol: (protocol) => `Invalid Ollama protocol: ${protocol}. Use http: or https:.`,
|
|
36
42
|
errorPrefix: "Error"
|
|
37
43
|
}
|
|
38
44
|
};
|
package/dist/messages/doctor.js
CHANGED
|
@@ -41,7 +41,7 @@ export const doctorMessages = {
|
|
|
41
41
|
promptModeInvalid: (name, value) => `${name}: promptMode invalide (${value}). Valeurs attendues: stdin ou argument.`,
|
|
42
42
|
positiveTimeout: (name, field) => `${name}: ${field} doit être un nombre positif.`,
|
|
43
43
|
ollamaModelMissing: (name) => `${name}: modèle Ollama absent.`,
|
|
44
|
-
ollamaBaseUrlInvalid: (name, value) => `${name}: baseUrl Ollama invalide (${value}). Attendu:
|
|
44
|
+
ollamaBaseUrlInvalid: (name, value) => `${name}: baseUrl Ollama invalide (${value}). Attendu: une adresse HTTP(S), avec ou sans schema.`,
|
|
45
45
|
customCommand: (prefix) => `${prefix} (commande custom non vérifiée par doctor)`,
|
|
46
46
|
cliDetected: (prefix, path) => `${prefix} détectée (${path})`,
|
|
47
47
|
cliMissing: (prefix) => `${prefix} non détectée dans PATH. Action: installe/authentifie la CLI ou corrige command dans la config.`,
|
|
@@ -107,7 +107,7 @@ export const doctorMessages = {
|
|
|
107
107
|
promptModeInvalid: (name, value) => `${name}: invalid promptMode (${value}). Expected values: stdin or argument.`,
|
|
108
108
|
positiveTimeout: (name, field) => `${name}: ${field} must be a positive number.`,
|
|
109
109
|
ollamaModelMissing: (name) => `${name}: missing Ollama model.`,
|
|
110
|
-
ollamaBaseUrlInvalid: (name, value) => `${name}: invalid Ollama baseUrl (${value}). Expected:
|
|
110
|
+
ollamaBaseUrlInvalid: (name, value) => `${name}: invalid Ollama baseUrl (${value}). Expected: an HTTP(S) address, with or without a scheme.`,
|
|
111
111
|
customCommand: (prefix) => `${prefix} (custom command not checked by doctor)`,
|
|
112
112
|
cliDetected: (prefix, path) => `${prefix} detected (${path})`,
|
|
113
113
|
cliMissing: (prefix) => `${prefix} not detected in PATH. Action: install/authenticate the CLI or fix command in the config.`,
|
package/dist/messages/help.js
CHANGED
|
@@ -22,6 +22,7 @@ Usage:
|
|
|
22
22
|
Flags:
|
|
23
23
|
--config <path> chemin de config explicite
|
|
24
24
|
--language <fr|en> force la langue
|
|
25
|
+
--json sortie JSON pour les integrations
|
|
25
26
|
`,
|
|
26
27
|
presets: `
|
|
27
28
|
Liste les presets de paires d'agents.
|
|
@@ -129,6 +130,7 @@ Flags:
|
|
|
129
130
|
--preset <name> preset d'agents
|
|
130
131
|
--agent-a <name> premier agent
|
|
131
132
|
--agent-b <name> second agent
|
|
133
|
+
--ollama-url <url> surcharge l'adresse Ollama pour cette session
|
|
132
134
|
--tui force l'interface TUI
|
|
133
135
|
--terminal force le rendu terminal brut
|
|
134
136
|
--renderer <kind> auto, pretty, plain, tui ou ndjson
|
|
@@ -144,6 +146,7 @@ Usage:
|
|
|
144
146
|
Flags:
|
|
145
147
|
--agents <names...> agents qui repondent, 4 maximum
|
|
146
148
|
--summary-agent <n> agent de synthese pour ce lancement
|
|
149
|
+
--ollama-url <url> surcharge l'adresse Ollama pour cette session
|
|
147
150
|
--tui force l'interface TUI
|
|
148
151
|
--terminal force le rendu terminal brut
|
|
149
152
|
--renderer <kind> auto, pretty, plain, tui ou ndjson
|
|
@@ -174,6 +177,7 @@ Usage:
|
|
|
174
177
|
Flags:
|
|
175
178
|
--config <path> explicit config path
|
|
176
179
|
--language <fr|en> forces the language
|
|
180
|
+
--json JSON output for integrations
|
|
177
181
|
`,
|
|
178
182
|
presets: `
|
|
179
183
|
Lists agent-pair presets.
|
|
@@ -281,6 +285,7 @@ Flags:
|
|
|
281
285
|
--preset <name> agent preset
|
|
282
286
|
--agent-a <name> first agent
|
|
283
287
|
--agent-b <name> second agent
|
|
288
|
+
--ollama-url <url> overrides the Ollama address for this session
|
|
284
289
|
--tui forces the TUI interface
|
|
285
290
|
--terminal forces raw terminal rendering
|
|
286
291
|
--renderer <kind> auto, pretty, plain, tui, or ndjson
|
|
@@ -296,6 +301,7 @@ Usage:
|
|
|
296
301
|
Flags:
|
|
297
302
|
--agents <names...> responding agents, 4 maximum
|
|
298
303
|
--summary-agent <n> summary agent for this run
|
|
304
|
+
--ollama-url <url> overrides the Ollama address for this session
|
|
299
305
|
--tui forces the TUI interface
|
|
300
306
|
--terminal forces raw terminal rendering
|
|
301
307
|
--renderer <kind> auto, pretty, plain, tui, or ndjson
|
package/dist/messages/tui.js
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
export const tuiMessages = {
|
|
2
2
|
fr: {
|
|
3
3
|
tagline: "Orchestrez des conversations entre agents IA",
|
|
4
|
+
updateAvailable: (current, latest) => `Mise a jour disponible: ${current} -> ${latest}. Utilise /update.`,
|
|
4
5
|
modeLabel: (mode) => mode === "ask" ? "Ask" : "Debat",
|
|
5
6
|
modeValue: (mode) => mode === "ask" ? "Ask" : "Debat",
|
|
6
7
|
noValue: "non definis",
|
|
@@ -8,6 +9,8 @@ export const tuiMessages = {
|
|
|
8
9
|
roles: "Roles",
|
|
9
10
|
summary: "Synthese",
|
|
10
11
|
ollamaModel: "Modele Ollama",
|
|
12
|
+
ollamaUrl: "Adresse Ollama configuree",
|
|
13
|
+
ollamaUrlEffective: "Adresse Ollama effective",
|
|
11
14
|
responses: "Tours",
|
|
12
15
|
folder: "Dossier",
|
|
13
16
|
docs: "Docs",
|
|
@@ -24,6 +27,7 @@ export const tuiMessages = {
|
|
|
24
27
|
helpNew: "assistant guide",
|
|
25
28
|
helpRetry: "relancer la derniere session",
|
|
26
29
|
helpHistory: "voir les derniers exports",
|
|
30
|
+
helpUpdate: "voir les informations de mise a jour",
|
|
27
31
|
helpHelp: "aide",
|
|
28
32
|
helpQuit: "quitter",
|
|
29
33
|
helpFallback: "Tape un sujet ou une commande.",
|
|
@@ -78,10 +82,12 @@ export const tuiMessages = {
|
|
|
78
82
|
turnsUsage: "Usage: /turns <tours>",
|
|
79
83
|
summaryUsage: "Usage: /summary <agent|none>",
|
|
80
84
|
ollamaModelUsage: "Usage: /ollama-model <modele>",
|
|
85
|
+
ollamaUrlUsage: "Usage: /ollama-url <url|default>",
|
|
81
86
|
interfaceUsage: "Usage: /interface <tui|terminal>",
|
|
82
87
|
languageUsage: "Usage: /language <fr|en>",
|
|
83
88
|
rolesUsage: "Usage: /roles <role...>",
|
|
84
89
|
ollamaInfoCommand: "afficher modeles installes",
|
|
90
|
+
ollamaUrlCommand: "modifier l'adresse (<url|default>)",
|
|
85
91
|
ollamaSyncCommand: "choisir un modele installe disponible",
|
|
86
92
|
interfaceDefault: (value) => `Interface par defaut: ${value}.`,
|
|
87
93
|
languageUpdated: (value) => `Langue mise a jour: ${value}.`,
|
|
@@ -98,6 +104,7 @@ export const tuiMessages = {
|
|
|
98
104
|
askSummaryAgent: (value) => `Synthese Ask: ${value}.`,
|
|
99
105
|
debateSummaryAgent: (value) => `Synthese Debat: ${value}.`,
|
|
100
106
|
ollamaInfo: (current, installed, api) => `Ollama ${api}. Modele actuel: ${current}. Modeles installes: ${installed}.`,
|
|
107
|
+
ollamaUrlUpdated: (configured, effective) => configured === effective ? `Adresse Ollama mise a jour: ${configured}.` : `Adresse Ollama configuree: ${configured}. Adresse effective via OLLAMA_HOST: ${effective}.`,
|
|
101
108
|
ollamaUnavailable: (baseUrl) => `API Ollama indisponible (${baseUrl}). Lance ollama serve puis reessaie /ollama.`,
|
|
102
109
|
askAgentsUpdated: (value) => `Agents Ask mis a jour: ${value}.`,
|
|
103
110
|
debateAgentsUpdated: (value) => `Agents Debat mis a jour: ${value}.`,
|
|
@@ -114,6 +121,7 @@ export const tuiMessages = {
|
|
|
114
121
|
},
|
|
115
122
|
en: {
|
|
116
123
|
tagline: "Orchestrate conversations between AI agents",
|
|
124
|
+
updateAvailable: (current, latest) => `Update available: ${current} -> ${latest}. Use /update.`,
|
|
117
125
|
modeLabel: (mode) => mode === "ask" ? "Ask" : "Debate",
|
|
118
126
|
modeValue: (mode) => mode === "ask" ? "Ask" : "Debate",
|
|
119
127
|
noValue: "not set",
|
|
@@ -121,6 +129,8 @@ export const tuiMessages = {
|
|
|
121
129
|
roles: "Roles",
|
|
122
130
|
summary: "Summary",
|
|
123
131
|
ollamaModel: "Ollama model",
|
|
132
|
+
ollamaUrl: "Configured Ollama address",
|
|
133
|
+
ollamaUrlEffective: "Effective Ollama address",
|
|
124
134
|
responses: "Turns",
|
|
125
135
|
folder: "Folder",
|
|
126
136
|
docs: "Docs",
|
|
@@ -137,6 +147,7 @@ export const tuiMessages = {
|
|
|
137
147
|
helpNew: "guided assistant",
|
|
138
148
|
helpRetry: "rerun the last session",
|
|
139
149
|
helpHistory: "show recent exports",
|
|
150
|
+
helpUpdate: "show update information",
|
|
140
151
|
helpHelp: "help",
|
|
141
152
|
helpQuit: "quit",
|
|
142
153
|
helpFallback: "Type a topic or a command.",
|
|
@@ -191,10 +202,12 @@ export const tuiMessages = {
|
|
|
191
202
|
turnsUsage: "Usage: /turns <turns>",
|
|
192
203
|
summaryUsage: "Usage: /summary <agent|none>",
|
|
193
204
|
ollamaModelUsage: "Usage: /ollama-model <model>",
|
|
205
|
+
ollamaUrlUsage: "Usage: /ollama-url <url|default>",
|
|
194
206
|
interfaceUsage: "Usage: /interface <tui|terminal>",
|
|
195
207
|
languageUsage: "Usage: /language <fr|en>",
|
|
196
208
|
rolesUsage: "Usage: /roles <role...>",
|
|
197
209
|
ollamaInfoCommand: "show installed models",
|
|
210
|
+
ollamaUrlCommand: "change the address (<url|default>)",
|
|
198
211
|
ollamaSyncCommand: "choose an available installed model",
|
|
199
212
|
interfaceDefault: (value) => `Default interface: ${value}.`,
|
|
200
213
|
languageUpdated: (value) => `Language updated: ${value}.`,
|
|
@@ -211,6 +224,7 @@ export const tuiMessages = {
|
|
|
211
224
|
askSummaryAgent: (value) => `Ask summary: ${value}.`,
|
|
212
225
|
debateSummaryAgent: (value) => `Debate summary: ${value}.`,
|
|
213
226
|
ollamaInfo: (current, installed, api) => `Ollama ${api}. Current model: ${current}. Installed models: ${installed}.`,
|
|
227
|
+
ollamaUrlUpdated: (configured, effective) => configured === effective ? `Ollama address updated: ${configured}.` : `Ollama address configured: ${configured}. Effective address from OLLAMA_HOST: ${effective}.`,
|
|
214
228
|
ollamaUnavailable: (baseUrl) => `Ollama API unavailable (${baseUrl}). Run ollama serve, then try /ollama again.`,
|
|
215
229
|
askAgentsUpdated: (value) => `Ask agents updated: ${value}.`,
|
|
216
230
|
debateAgentsUpdated: (value) => `Debate agents updated: ${value}.`,
|
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
export const DEFAULT_OLLAMA_BASE_URL = "http://localhost:11434";
|
|
2
|
+
export class OllamaUrlError extends Error {
|
|
3
|
+
kind;
|
|
4
|
+
value;
|
|
5
|
+
protocol;
|
|
6
|
+
constructor(kind, value, protocol) {
|
|
7
|
+
super(kind === "empty"
|
|
8
|
+
? "Invalid Ollama URL: the value is empty."
|
|
9
|
+
: kind === "protocol"
|
|
10
|
+
? `Invalid Ollama URL protocol: ${protocol ?? ""}`
|
|
11
|
+
: `Invalid Ollama URL: ${value}`);
|
|
12
|
+
this.kind = kind;
|
|
13
|
+
this.value = value;
|
|
14
|
+
this.protocol = protocol;
|
|
15
|
+
this.name = "OllamaUrlError";
|
|
16
|
+
}
|
|
17
|
+
}
|
|
18
|
+
/**
|
|
19
|
+
* Résout l'adresse client Ollama selon la priorité produit :
|
|
20
|
+
* flag CLI > OLLAMA_HOST > config agent > serveur local par défaut.
|
|
21
|
+
*/
|
|
22
|
+
export function resolveOllamaBaseUrl(sources = {}) {
|
|
23
|
+
const value = firstNonEmpty(sources.cliUrl, sources.envUrl ?? process.env.OLLAMA_HOST, sources.configUrl, DEFAULT_OLLAMA_BASE_URL);
|
|
24
|
+
return normalizeOllamaBaseUrl(value);
|
|
25
|
+
}
|
|
26
|
+
/** Normalise les formats acceptés par Ollama en URL HTTP(S) utilisable par fetch. */
|
|
27
|
+
export function normalizeOllamaBaseUrl(value) {
|
|
28
|
+
const trimmed = value.trim();
|
|
29
|
+
if (!trimmed) {
|
|
30
|
+
throw new OllamaUrlError("empty", value);
|
|
31
|
+
}
|
|
32
|
+
const withHost = trimmed.startsWith(":") ? `127.0.0.1${trimmed}` : trimmed;
|
|
33
|
+
const hasExplicitScheme = withHost.includes("://");
|
|
34
|
+
const withScheme = hasExplicitScheme ? withHost : `http://${withHost}`;
|
|
35
|
+
let url;
|
|
36
|
+
try {
|
|
37
|
+
url = new URL(withScheme);
|
|
38
|
+
}
|
|
39
|
+
catch {
|
|
40
|
+
throw new OllamaUrlError("invalid", value);
|
|
41
|
+
}
|
|
42
|
+
if (url.protocol !== "http:" && url.protocol !== "https:") {
|
|
43
|
+
throw new OllamaUrlError("protocol", value, url.protocol);
|
|
44
|
+
}
|
|
45
|
+
if (!url.hostname || url.username || url.password || url.search || url.hash) {
|
|
46
|
+
throw new OllamaUrlError("invalid", value);
|
|
47
|
+
}
|
|
48
|
+
if (!hasExplicitScheme && !url.port) {
|
|
49
|
+
url.port = "11434";
|
|
50
|
+
}
|
|
51
|
+
if (url.hostname === "0.0.0.0") {
|
|
52
|
+
url.hostname = "127.0.0.1";
|
|
53
|
+
}
|
|
54
|
+
else if (url.hostname === "[::]") {
|
|
55
|
+
url.hostname = "[::1]";
|
|
56
|
+
}
|
|
57
|
+
return url.toString().replace(/\/+$/, "");
|
|
58
|
+
}
|
|
59
|
+
/** Retourne l'URL configurée pour l'agent Ollama principal, puis le premier agent Ollama. */
|
|
60
|
+
export function configuredOllamaBaseUrl(config) {
|
|
61
|
+
const primary = config.agents["ollama-local"];
|
|
62
|
+
if (primary?.type === "ollama" && primary.baseUrl) {
|
|
63
|
+
return primary.baseUrl;
|
|
64
|
+
}
|
|
65
|
+
const configured = Object.values(config.agents).find((agent) => agent.type === "ollama" && agent.baseUrl);
|
|
66
|
+
return configured?.type === "ollama" ? configured.baseUrl : undefined;
|
|
67
|
+
}
|
|
68
|
+
/** Retourne les URL configurées par nom d'agent Ollama. */
|
|
69
|
+
export function configuredOllamaTargets(config) {
|
|
70
|
+
return Object.fromEntries(Object.entries(config.agents)
|
|
71
|
+
.filter(([, agent]) => agent.type === "ollama")
|
|
72
|
+
.map(([name, agent]) => [name, agent.type === "ollama" ? agent.baseUrl : undefined]));
|
|
73
|
+
}
|
|
74
|
+
function firstNonEmpty(...values) {
|
|
75
|
+
return values.find((value) => Boolean(value?.trim())) ?? DEFAULT_OLLAMA_BASE_URL;
|
|
76
|
+
}
|
package/dist/orchestrator.js
CHANGED
|
@@ -1,7 +1,9 @@
|
|
|
1
1
|
import { createAgent } from "./adapters/index.js";
|
|
2
2
|
import { AdapterError } from "./errors.js";
|
|
3
3
|
import { createTranslator } from "./i18n.js";
|
|
4
|
-
|
|
4
|
+
import { MAX_ASK_AGENTS } from "./limits.js";
|
|
5
|
+
import { OllamaUrlError } from "./ollamaUrl.js";
|
|
6
|
+
export { MAX_ASK_AGENTS } from "./limits.js";
|
|
5
7
|
/**
|
|
6
8
|
* Point d'entrée de l'orchestration.
|
|
7
9
|
* Lance le ping-pong entre `agentA` et `agentB` pendant `options.turns` tours,
|
|
@@ -27,8 +29,8 @@ export async function runDebate(config, options, renderer, messages = createTran
|
|
|
27
29
|
{ name: options.agentB, role: agentBConfig.role, type: agentBConfig.type }
|
|
28
30
|
]);
|
|
29
31
|
const agents = [
|
|
30
|
-
createAgent(options.agentA, agentAConfig),
|
|
31
|
-
createAgent(options.agentB, agentBConfig)
|
|
32
|
+
createAgent(options.agentA, agentAConfig, { ollamaUrl: options.ollamaUrl }),
|
|
33
|
+
createAgent(options.agentB, agentBConfig, { ollamaUrl: options.ollamaUrl })
|
|
32
34
|
];
|
|
33
35
|
const transcript = [];
|
|
34
36
|
let stopReason;
|
|
@@ -73,7 +75,7 @@ export async function runDebate(config, options, renderer, messages = createTran
|
|
|
73
75
|
agent: current.name,
|
|
74
76
|
role: current.role,
|
|
75
77
|
turn
|
|
76
|
-
});
|
|
78
|
+
}, messages);
|
|
77
79
|
renderer?.error(failure);
|
|
78
80
|
return {
|
|
79
81
|
options,
|
|
@@ -105,7 +107,7 @@ export async function runDebate(config, options, renderer, messages = createTran
|
|
|
105
107
|
try {
|
|
106
108
|
const cancellation = cancellationFailureIfAborted(options, messages, {
|
|
107
109
|
phase: "summary",
|
|
108
|
-
agent:
|
|
110
|
+
agent: options.summaryAgent,
|
|
109
111
|
role: summaryRole(),
|
|
110
112
|
turn: transcript.length + 1
|
|
111
113
|
});
|
|
@@ -123,10 +125,10 @@ export async function runDebate(config, options, renderer, messages = createTran
|
|
|
123
125
|
catch (error) {
|
|
124
126
|
failure = toDebateFailure(error, {
|
|
125
127
|
phase: "summary",
|
|
126
|
-
agent:
|
|
128
|
+
agent: options.summaryAgent,
|
|
127
129
|
role: summaryRole(),
|
|
128
130
|
turn: transcript.length + 1
|
|
129
|
-
});
|
|
131
|
+
}, messages);
|
|
130
132
|
renderer?.error(failure);
|
|
131
133
|
}
|
|
132
134
|
}
|
|
@@ -163,7 +165,7 @@ export async function runAsk(config, options, renderer, messages = createTransla
|
|
|
163
165
|
role: agentConfig.role,
|
|
164
166
|
type: agentConfig.type
|
|
165
167
|
})));
|
|
166
|
-
const agents = agentEntries.map(([name, agentConfig]) => createAgent(name, agentConfig));
|
|
168
|
+
const agents = agentEntries.map(([name, agentConfig]) => createAgent(name, agentConfig, { ollamaUrl: options.ollamaUrl }));
|
|
167
169
|
const transcript = [];
|
|
168
170
|
for (let index = 0; index < agents.length; index += 1) {
|
|
169
171
|
const current = agents[index];
|
|
@@ -212,7 +214,7 @@ export async function runAsk(config, options, renderer, messages = createTransla
|
|
|
212
214
|
agent: current.name,
|
|
213
215
|
role: current.role,
|
|
214
216
|
turn: response
|
|
215
|
-
});
|
|
217
|
+
}, messages);
|
|
216
218
|
renderer?.error(failure);
|
|
217
219
|
return {
|
|
218
220
|
options,
|
|
@@ -241,7 +243,7 @@ export async function runAsk(config, options, renderer, messages = createTransla
|
|
|
241
243
|
let failure;
|
|
242
244
|
if (options.summaryEnabled) {
|
|
243
245
|
try {
|
|
244
|
-
const summaryAgentName =
|
|
246
|
+
const summaryAgentName = options.summaryAgent;
|
|
245
247
|
const cancellation = cancellationFailureIfAborted(options, messages, {
|
|
246
248
|
phase: "summary",
|
|
247
249
|
agent: summaryAgentName,
|
|
@@ -261,10 +263,10 @@ export async function runAsk(config, options, renderer, messages = createTransla
|
|
|
261
263
|
catch (error) {
|
|
262
264
|
failure = toDebateFailure(error, {
|
|
263
265
|
phase: "summary",
|
|
264
|
-
agent:
|
|
266
|
+
agent: options.summaryAgent,
|
|
265
267
|
role: summaryRole(),
|
|
266
268
|
turn: transcript.length + 1
|
|
267
|
-
});
|
|
269
|
+
}, messages);
|
|
268
270
|
renderer?.error(failure);
|
|
269
271
|
}
|
|
270
272
|
}
|
|
@@ -329,13 +331,13 @@ function warnIfOllamaHasNoContext(options, agents, renderer, messages = createTr
|
|
|
329
331
|
* @throws {Error} si l'agent de synthèse est absent de `config.agents`.
|
|
330
332
|
*/
|
|
331
333
|
async function generateSummary(config, options, transcript, renderer, messages = createTranslator("fr")) {
|
|
332
|
-
const summaryAgentName =
|
|
334
|
+
const summaryAgentName = options.summaryAgent;
|
|
333
335
|
const summaryModel = options.summaryModel ?? modelForAgent(options, summaryAgentName);
|
|
334
336
|
const summaryConfig = withRuntimeOverrides(config.agents[summaryAgentName], summaryModel, options.pullModels);
|
|
335
337
|
if (!summaryConfig) {
|
|
336
338
|
throw new Error(messages.orchestrator.unknownSummaryAgent(summaryAgentName));
|
|
337
339
|
}
|
|
338
|
-
const summaryAgent = createAgent(summaryAgentName, summaryConfig);
|
|
340
|
+
const summaryAgent = createAgent(summaryAgentName, summaryConfig, { ollamaUrl: options.ollamaUrl });
|
|
339
341
|
const role = summaryRole();
|
|
340
342
|
renderer?.summaryStart(summaryAgent.name, role);
|
|
341
343
|
renderer?.thinkingStart(summaryAgent.name, role);
|
|
@@ -384,16 +386,7 @@ function resolveAskAgentNames(options) {
|
|
|
384
386
|
: [options.agentA, options.agentB];
|
|
385
387
|
return agents.filter((agent, index) => Boolean(agent) && agents.indexOf(agent) === index);
|
|
386
388
|
}
|
|
387
|
-
function
|
|
388
|
-
if (options.summaryAgent) {
|
|
389
|
-
return options.summaryAgent;
|
|
390
|
-
}
|
|
391
|
-
if (options.mode === "ask" && options.askAgents && options.askAgents.length > 0) {
|
|
392
|
-
return options.askAgents[options.askAgents.length - 1] ?? options.agentB;
|
|
393
|
-
}
|
|
394
|
-
return options.agentB;
|
|
395
|
-
}
|
|
396
|
-
function toDebateFailure(error, context) {
|
|
389
|
+
function toDebateFailure(error, context, messages) {
|
|
397
390
|
if (error instanceof AdapterError) {
|
|
398
391
|
return {
|
|
399
392
|
phase: context.phase,
|
|
@@ -405,6 +398,18 @@ function toDebateFailure(error, context) {
|
|
|
405
398
|
details: error.details
|
|
406
399
|
};
|
|
407
400
|
}
|
|
401
|
+
if (error instanceof OllamaUrlError) {
|
|
402
|
+
const message = error.kind === "empty"
|
|
403
|
+
? messages.common.ollamaUrlEmpty
|
|
404
|
+
: error.kind === "protocol"
|
|
405
|
+
? messages.common.ollamaUrlProtocol(error.protocol ?? "")
|
|
406
|
+
: messages.common.ollamaUrlInvalid(error.value);
|
|
407
|
+
return {
|
|
408
|
+
...context,
|
|
409
|
+
kind: "unknown",
|
|
410
|
+
message
|
|
411
|
+
};
|
|
412
|
+
}
|
|
408
413
|
return {
|
|
409
414
|
phase: context.phase,
|
|
410
415
|
agent: context.agent,
|
package/dist/output.js
CHANGED
|
@@ -94,7 +94,7 @@ function renderSessionHeader(options, debateMessages, stopReason, messages) {
|
|
|
94
94
|
[messages.output.fields.mode, options.mode],
|
|
95
95
|
[messages.output.fields.agents, formatAgentsForHeader(options)],
|
|
96
96
|
[messages.output.fields.autoPullOllama, options.pullModels ? messages.output.yes : messages.output.no],
|
|
97
|
-
[messages.output.fields.summary, options.summaryEnabled ?
|
|
97
|
+
[messages.output.fields.summary, options.summaryEnabled ? options.summaryAgent : messages.output.disabled],
|
|
98
98
|
[
|
|
99
99
|
options.mode === "ask" ? messages.output.fields.requestedResponses : messages.output.fields.requestedTurns,
|
|
100
100
|
String(options.mode === "ask" ? options.askAgents?.length ?? debateMessages.length : options.turns)
|
|
@@ -124,15 +124,6 @@ function renderFileList(files, messages) {
|
|
|
124
124
|
}
|
|
125
125
|
return files.map((file) => `- \`${file.path}\` (${file.sizeBytes} ${messages.output.fileSizeUnit})`);
|
|
126
126
|
}
|
|
127
|
-
function formatSummaryAgent(options) {
|
|
128
|
-
if (options.summaryAgent) {
|
|
129
|
-
return options.summaryAgent;
|
|
130
|
-
}
|
|
131
|
-
if (options.mode === "ask" && options.askAgents && options.askAgents.length > 0) {
|
|
132
|
-
return options.askAgents[options.askAgents.length - 1] ?? options.agentB;
|
|
133
|
-
}
|
|
134
|
-
return options.agentB;
|
|
135
|
-
}
|
|
136
127
|
function formatAgentsForHeader(options) {
|
|
137
128
|
if (options.mode === "ask") {
|
|
138
129
|
return (options.askAgents && options.askAgents.length > 0 ? options.askAgents : [options.agentA, options.agentB]).join(", ");
|
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",
|
|
@@ -161,6 +161,26 @@ export function listPresetsWithAvailability(config, discovery, messages) {
|
|
|
161
161
|
};
|
|
162
162
|
});
|
|
163
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
|
+
}
|
|
164
184
|
/** Recherche inverse : retourne le nom du preset correspondant à une paire `(agentA, agentB)`, ou `undefined`. */
|
|
165
185
|
export function findPresetNameForPair(agentA, agentB) {
|
|
166
186
|
return Object.entries(presets).find(([, preset]) => preset.agentA === agentA && preset.agentB === agentB)?.[0];
|
|
@@ -171,12 +191,13 @@ function checkAgentAvailability(agentName, config, discovery, messages) {
|
|
|
171
191
|
return unavailable(agentName, messages?.presets.missingAgent(agentName) ?? `agent absent de la config: ${agentName}`);
|
|
172
192
|
}
|
|
173
193
|
if (agent.type === "ollama") {
|
|
174
|
-
|
|
175
|
-
|
|
194
|
+
const ollama = discovery.ollamaAgents?.[agentName] ?? discovery.ollama;
|
|
195
|
+
if (!ollama.available) {
|
|
196
|
+
return unavailable(agentName, ollama.commandAvailable
|
|
176
197
|
? messages?.presets.ollamaUnreachable(agentName) ?? `Ollama non joignable pour ${agentName}`
|
|
177
198
|
: messages?.presets.ollamaNotDetected(agentName) ?? `Ollama non détecté pour ${agentName}`);
|
|
178
199
|
}
|
|
179
|
-
if (!
|
|
200
|
+
if (!ollama.models.includes(agent.model)) {
|
|
180
201
|
return unavailable(agentName, messages?.presets.missingOllamaModel(agentName, agent.model) ?? `modèle Ollama absent pour ${agentName}: ${agent.model}`);
|
|
181
202
|
}
|
|
182
203
|
return available(agentName);
|
|
@@ -241,13 +241,7 @@ function formatSummary(options, messages) {
|
|
|
241
241
|
if (!options.summaryEnabled) {
|
|
242
242
|
return messages.renderers.disabled;
|
|
243
243
|
}
|
|
244
|
-
|
|
245
|
-
return options.summaryAgent;
|
|
246
|
-
}
|
|
247
|
-
if (options.mode === "ask" && options.askAgents && options.askAgents.length > 0) {
|
|
248
|
-
return options.askAgents[options.askAgents.length - 1] ?? options.agentB;
|
|
249
|
-
}
|
|
250
|
-
return options.agentB;
|
|
244
|
+
return options.summaryAgent;
|
|
251
245
|
}
|
|
252
246
|
function formatResponseCount(options) {
|
|
253
247
|
return options.mode === "ask" ? options.askAgents?.length ?? 2 : options.turns;
|
package/dist/renderers/ndjson.js
CHANGED
|
@@ -31,7 +31,7 @@ export class NdjsonRenderer {
|
|
|
31
31
|
agents: agents.map((a) => ({ name: a.name, role: a.role, type: a.type })),
|
|
32
32
|
summaryEnabled: options.summaryEnabled,
|
|
33
33
|
summaryAgent: options.summaryEnabled
|
|
34
|
-
?
|
|
34
|
+
? options.summaryAgent
|
|
35
35
|
: null,
|
|
36
36
|
earlyStop: options.earlyStopOnAgreement,
|
|
37
37
|
filesCount: options.files.length,
|
|
@@ -134,15 +134,6 @@ export class NdjsonRenderer {
|
|
|
134
134
|
process.stdout.write(JSON.stringify({ v: this.schemaVersion, ...event }) + "\n");
|
|
135
135
|
}
|
|
136
136
|
}
|
|
137
|
-
function resolveSummaryAgent(options) {
|
|
138
|
-
if (options.summaryAgent) {
|
|
139
|
-
return options.summaryAgent;
|
|
140
|
-
}
|
|
141
|
-
if (options.mode === "ask" && options.askAgents && options.askAgents.length > 0) {
|
|
142
|
-
return options.askAgents[options.askAgents.length - 1] ?? options.agentB;
|
|
143
|
-
}
|
|
144
|
-
return options.agentB;
|
|
145
|
-
}
|
|
146
137
|
/** Factory pratique pour conserver la symétrie avec `createConsoleRenderer`. */
|
|
147
138
|
export function createNdjsonRenderer() {
|
|
148
139
|
return new NdjsonRenderer();
|