@imenam/mcp-messenger 1.0.6 → 1.0.8
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/.env.example +6 -3
- package/README.md +53 -13
- package/dist/src/cli/setup-mcp.js +1 -1
- package/dist/src/cli/watch.js +2 -2
- package/dist/src/client/messenger-client.d.ts +2 -3
- package/dist/src/client/messenger-client.js +3 -3
- package/dist/src/config.d.ts +3 -2
- package/dist/src/config.js +2 -2
- package/dist/src/core/store.d.ts +23 -8
- package/dist/src/core/store.js +65 -42
- package/dist/src/core/types.d.ts +19 -9
- package/dist/src/core/types.js +2 -2
- package/dist/src/mcp/start.js +21 -1
- package/dist/src/mcp/tools.js +122 -63
- package/dist/src/server/app.js +18 -14
- package/dist/src/server/ui/app.js +320 -318
- package/dist/src/server/ui/styles.css +5 -0
- package/dist/src/version.d.ts +1 -1
- package/dist/src/version.js +1 -1
- package/package.json +1 -1
package/dist/src/mcp/tools.js
CHANGED
|
@@ -25,24 +25,37 @@ export const TOOLS = [
|
|
|
25
25
|
},
|
|
26
26
|
},
|
|
27
27
|
{
|
|
28
|
-
name: "
|
|
29
|
-
description: "Give a plain-language name to this mailbox, or
|
|
28
|
+
name: "rename_mailbox",
|
|
29
|
+
description: "Give a plain-language name to this mailbox, or change it: what this session is working on, e.g. 'Développement des tests unitaires du parser'. Addresses are opaque: the name is what makes this session recognisable later, both for the other agents (list_agents) and for the user reading the web console. It does not touch the agent name, which says where the agent comes from (its project) and is set by the configuration.",
|
|
30
|
+
inputSchema: {
|
|
31
|
+
type: "object",
|
|
32
|
+
properties: {
|
|
33
|
+
name: { type: "string", description: "Short name, one line. Say what the work is about, not who does it." },
|
|
34
|
+
description: { type: "string", description: "Optional longer explanation of what this mailbox is for." },
|
|
35
|
+
},
|
|
36
|
+
additionalProperties: false,
|
|
37
|
+
},
|
|
38
|
+
},
|
|
39
|
+
{
|
|
40
|
+
name: "rename_thread",
|
|
41
|
+
description: "Give a plain-language name to a thread, or change it, e.g. 'Le test échoue sur un bug applicatif'. A thread has a single shared name: renaming it changes it for every participant, and the last caller wins. Use it when a thread was opened without a name, or when the discussion has drifted away from its original name.",
|
|
30
42
|
inputSchema: {
|
|
31
43
|
type: "object",
|
|
32
44
|
properties: {
|
|
33
|
-
label: { type: "string", description: "Short name, one line. Say what the work is about, not who does it." },
|
|
34
|
-
description: { type: "string", description: "Optional longer explanation of the mailbox or the thread." },
|
|
35
45
|
thread_id: {
|
|
36
46
|
type: "string",
|
|
37
|
-
description: "Thread to
|
|
47
|
+
description: "Thread to rename. You must be a participant of the thread.",
|
|
38
48
|
},
|
|
49
|
+
name: { type: "string", description: "Short name, one line. Say what the thread is about." },
|
|
50
|
+
description: { type: "string", description: "Optional longer explanation of the thread." },
|
|
39
51
|
},
|
|
52
|
+
required: ["thread_id"],
|
|
40
53
|
additionalProperties: false,
|
|
41
54
|
},
|
|
42
55
|
},
|
|
43
56
|
{
|
|
44
57
|
name: "list_threads",
|
|
45
|
-
description: "List the conversations visible from this mailbox, most recently active first, with their name, participants and unread count. This is the readable map of the ongoing work: prefer it over list_messages when you want to know what is being discussed rather than what arrived last. A thread with no name falls back to the subject of its opening message — name it with
|
|
58
|
+
description: "List the conversations visible from this mailbox, most recently active first, with their name, participants and unread count. This is the readable map of the ongoing work: prefer it over list_messages when you want to know what is being discussed rather than what arrived last. A thread with no name falls back to the subject of its opening message — name it with rename_thread.",
|
|
46
59
|
inputSchema: {
|
|
47
60
|
type: "object",
|
|
48
61
|
properties: {
|
|
@@ -55,29 +68,26 @@ export const TOOLS = [
|
|
|
55
68
|
},
|
|
56
69
|
{
|
|
57
70
|
name: "list_agents",
|
|
58
|
-
description: "List the agents known to the mailbox server, most recently active first, with their name and description. Use it to find the address of the agent you want to write to.",
|
|
71
|
+
description: "List the other agents known to the mailbox server, most recently active first, with their name and description. Your own mailbox is never listed — you cannot write to yourself. Use it to find the address of the agent you want to write to.",
|
|
59
72
|
inputSchema: { type: "object", properties: {}, additionalProperties: false },
|
|
60
73
|
},
|
|
61
74
|
{
|
|
62
75
|
name: "send_message",
|
|
63
|
-
description: "Send a message to one
|
|
76
|
+
description: "Send a message to one agent, identified by its mailbox address. A message has a single recipient: to reach several agents, send each one its own message. Set reply_to to answer an existing message and keep the thread together. Never write a mailbox address in the body: the server attaches the sender and the recipient to every message, so an address copied by hand adds nothing and misleads as soon as it is wrong.",
|
|
64
77
|
inputSchema: {
|
|
65
78
|
type: "object",
|
|
66
79
|
properties: {
|
|
67
|
-
to: {
|
|
68
|
-
type: "array",
|
|
69
|
-
items: { type: "string" },
|
|
70
|
-
minItems: 1,
|
|
71
|
-
description: "Recipient agent ids (mailbox addresses).",
|
|
72
|
-
},
|
|
73
|
-
cc: { type: "array", items: { type: "string" }, description: "Agents to keep in copy." },
|
|
80
|
+
to: { type: "string", description: "Recipient agent id (mailbox address). Exactly one recipient." },
|
|
74
81
|
subject: { type: "string", description: "Short subject line." },
|
|
75
|
-
body: {
|
|
82
|
+
body: {
|
|
83
|
+
type: "string",
|
|
84
|
+
description: "Message body, plain text or markdown. Do not restate your own address or the recipient's here.",
|
|
85
|
+
},
|
|
76
86
|
priority: { type: "string", enum: [...PRIORITIES], description: "Defaults to normal." },
|
|
77
87
|
reply_to: { type: "string", description: "Id of the message being answered; the reply joins its thread." },
|
|
78
|
-
|
|
88
|
+
thread_name: {
|
|
79
89
|
type: "string",
|
|
80
|
-
description: "Plain-language name of the conversation, e.g. 'Résolution de l'échec du test de parsing'. Name the thread when you open it — you already know what it is about. On a reply it renames the thread for everyone
|
|
90
|
+
description: "Plain-language name of the conversation, e.g. 'Résolution de l'échec du test de parsing'. Name the thread when you open it — you already know what it is about. On a reply it renames the thread for everyone (same effect as rename_thread).",
|
|
81
91
|
},
|
|
82
92
|
thread_description: { type: "string", description: "Optional longer description of the thread." },
|
|
83
93
|
},
|
|
@@ -210,13 +220,12 @@ export const TOOLS = [
|
|
|
210
220
|
];
|
|
211
221
|
const schemas = {
|
|
212
222
|
send_message: z.object({
|
|
213
|
-
to: z.
|
|
214
|
-
cc: z.union([z.string(), z.array(z.string())]).optional(),
|
|
223
|
+
to: z.string().min(1),
|
|
215
224
|
subject: z.string().min(1),
|
|
216
225
|
body: z.string().min(1),
|
|
217
226
|
priority: z.enum(PRIORITIES).optional(),
|
|
218
227
|
reply_to: z.string().optional(),
|
|
219
|
-
|
|
228
|
+
thread_name: z.string().trim().min(1).max(200).optional(),
|
|
220
229
|
thread_description: z.string().trim().min(1).max(2000).optional(),
|
|
221
230
|
}),
|
|
222
231
|
list_messages: z.object({
|
|
@@ -238,6 +247,24 @@ const schemas = {
|
|
|
238
247
|
move_messages: z.object({ message_ids: z.array(z.string().min(1)).min(1), folder: z.string().min(1) }),
|
|
239
248
|
delete_messages: z.object({ message_ids: z.array(z.string().min(1)).min(1), permanent: z.boolean().optional() }),
|
|
240
249
|
attach_to_mailbox: z.object({ mailbox_id: z.string().trim().min(1).optional() }),
|
|
250
|
+
rename_mailbox: z
|
|
251
|
+
.object({
|
|
252
|
+
name: z.string().trim().min(1).max(200).optional(),
|
|
253
|
+
description: z.string().trim().min(1).max(2000).optional(),
|
|
254
|
+
})
|
|
255
|
+
.refine((v) => v.name !== undefined || v.description !== undefined, {
|
|
256
|
+
message: "provide `name` and/or `description`",
|
|
257
|
+
}),
|
|
258
|
+
rename_thread: z
|
|
259
|
+
.object({
|
|
260
|
+
thread_id: z.string().trim().min(1),
|
|
261
|
+
name: z.string().trim().min(1).max(200).optional(),
|
|
262
|
+
description: z.string().trim().min(1).max(2000).optional(),
|
|
263
|
+
})
|
|
264
|
+
.refine((v) => v.name !== undefined || v.description !== undefined, {
|
|
265
|
+
message: "provide `name` and/or `description`",
|
|
266
|
+
}),
|
|
267
|
+
// Ancien outil `set_label` : une seule entrée pour la boîte et le fil, `label` au lieu de `name`.
|
|
241
268
|
set_label: z
|
|
242
269
|
.object({
|
|
243
270
|
label: z.string().trim().min(1).max(200).optional(),
|
|
@@ -273,9 +300,15 @@ export async function callTool(client, name, rawArgs) {
|
|
|
273
300
|
const lines = [
|
|
274
301
|
`Mailbox address: ${client.agentId}`,
|
|
275
302
|
" ↳ give this address to another agent so it can write to you.",
|
|
303
|
+
self?.agent_name
|
|
304
|
+
? `Agent: ${self.agent_name}`
|
|
305
|
+
: "Agent: unnamed (set MESSENGER_AGENT_NAME in the MCP configuration)",
|
|
306
|
+
// Le nom vient de la configuration : toutes les sessions du projet le portent. Le
|
|
307
|
+
// dire ici évite qu'un agent prenne une session homonyme pour la sienne.
|
|
308
|
+
" ↳ this name is shared with every session of the same project; only the address above identifies you.",
|
|
276
309
|
self?.display_name
|
|
277
310
|
? `Mailbox name: ${self.display_name}`
|
|
278
|
-
: "Mailbox name: none — call
|
|
311
|
+
: "Mailbox name: none — call rename_mailbox so the user can tell this session apart from the others.",
|
|
279
312
|
];
|
|
280
313
|
if (client.isAttachedElsewhere) {
|
|
281
314
|
lines.push(`Attached to another mailbox. This session's own mailbox is ${client.sessionAgentId}.`);
|
|
@@ -303,8 +336,9 @@ export async function callTool(client, name, rawArgs) {
|
|
|
303
336
|
client.setAgentId(target.id);
|
|
304
337
|
const attachedStats = await client.stats();
|
|
305
338
|
return [
|
|
306
|
-
`Attached to mailbox ${target.id}${target
|
|
307
|
-
target.
|
|
339
|
+
`Attached to mailbox ${target.id}${formatAgentNames(target) ? ` (${formatAgentNames(target)})` : ""}.`,
|
|
340
|
+
target.agent_description ? `Agent: ${target.agent_description}` : null,
|
|
341
|
+
target.description ? `Mailbox: ${target.description}` : null,
|
|
308
342
|
`Unread (excluding trash): ${attachedStats.unread_total}`,
|
|
309
343
|
client.sessionAgentId && client.sessionAgentId !== target.id
|
|
310
344
|
? `This session's own mailbox remains ${client.sessionAgentId} — attach_to_mailbox with no argument goes back to it.`
|
|
@@ -313,29 +347,24 @@ export async function callTool(client, name, rawArgs) {
|
|
|
313
347
|
.filter(Boolean)
|
|
314
348
|
.join("\n");
|
|
315
349
|
}
|
|
316
|
-
|
|
317
|
-
|
|
350
|
+
case "rename_mailbox": {
|
|
351
|
+
const input = schemas.rename_mailbox.parse(args);
|
|
352
|
+
return renameMailbox(client, input.name ?? null, input.description ?? null);
|
|
353
|
+
}
|
|
354
|
+
case "rename_thread": {
|
|
355
|
+
const input = schemas.rename_thread.parse(args);
|
|
356
|
+
return renameThread(client, input.thread_id, input.name ?? null, input.description ?? null);
|
|
357
|
+
}
|
|
358
|
+
// `set_label` et `set_mailbox_label` ne sont plus publiés, mais restent acceptés : une
|
|
359
|
+
// session en cours peut les avoir appris avant la mise à jour du serveur. Le mot « label »
|
|
360
|
+
// faisait penser à une étiquette, alors qu'il s'agissait du nom.
|
|
318
361
|
case "set_mailbox_label":
|
|
319
362
|
case "set_label": {
|
|
320
363
|
const input = schemas.set_label.parse(args);
|
|
321
364
|
if (input.thread_id) {
|
|
322
|
-
|
|
323
|
-
title: input.label ?? null,
|
|
324
|
-
description: input.description ?? null,
|
|
325
|
-
});
|
|
326
|
-
return [
|
|
327
|
-
`Thread ${thread.thread_id} is now named "${thread.title}".`,
|
|
328
|
-
thread.description ? `Description: ${thread.description}` : null,
|
|
329
|
-
"Every participant of the thread sees this name.",
|
|
330
|
-
]
|
|
331
|
-
.filter(Boolean)
|
|
332
|
-
.join("\n");
|
|
365
|
+
return renameThread(client, input.thread_id, input.label ?? null, input.description ?? null);
|
|
333
366
|
}
|
|
334
|
-
|
|
335
|
-
display_name: input.label ?? null,
|
|
336
|
-
description: input.description ?? null,
|
|
337
|
-
});
|
|
338
|
-
return `Mailbox ${agent.id} named "${agent.display_name}".`;
|
|
367
|
+
return renameMailbox(client, input.label ?? null, input.description ?? null);
|
|
339
368
|
}
|
|
340
369
|
case "list_threads": {
|
|
341
370
|
const input = schemas.list_threads.parse(args);
|
|
@@ -347,41 +376,54 @@ export async function callTool(client, name, rawArgs) {
|
|
|
347
376
|
case "list_agents": {
|
|
348
377
|
const agents = await client.listAgents();
|
|
349
378
|
if (agents.length === 0)
|
|
350
|
-
return "No agent
|
|
351
|
-
|
|
379
|
+
return "No other agent on this server yet.";
|
|
380
|
+
const directory = agents
|
|
352
381
|
.map((agent) => {
|
|
353
|
-
const flags =
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
const title = agent.display_name ? `${agent.id} — ${agent.display_name}` : agent.id;
|
|
382
|
+
const flags = agent.registered ? "" : "never connected";
|
|
383
|
+
const names = formatAgentNames(agent);
|
|
384
|
+
const title = names ? `${agent.id} — ${names}` : agent.id;
|
|
357
385
|
// L'annuaire est classé par cette date : l'afficher rend l'ordre lisible.
|
|
358
386
|
const seen = agent.last_activity_at ? `last active ${agent.last_activity_at}` : "never active";
|
|
359
|
-
return [
|
|
387
|
+
return [
|
|
388
|
+
`• ${title}${flags ? ` (${flags})` : ""}`,
|
|
389
|
+
` ${agent.agent_description ?? agent.description ?? "no description"}`,
|
|
390
|
+
` ${seen}`,
|
|
391
|
+
].join("\n");
|
|
360
392
|
})
|
|
361
393
|
.join("\n");
|
|
394
|
+
// Un nom d'agent est celui d'un projet, pas d'une session : plusieurs boîtes le
|
|
395
|
+
// portent, y compris celle de l'appelant. Sans ce rappel, un agent croise son propre
|
|
396
|
+
// nom d'agent dans cette liste et prend la boîte d'une autre session pour la sienne.
|
|
397
|
+
return [
|
|
398
|
+
directory,
|
|
399
|
+
"",
|
|
400
|
+
"Addresses identify sessions; agent names do not. Several mailboxes above may carry the same",
|
|
401
|
+
"agent name as yours — they are other sessions of the same project, never you: your own mailbox",
|
|
402
|
+
"is never listed here. Always write to an address taken from this list, never to a name.",
|
|
403
|
+
].join("\n");
|
|
362
404
|
}
|
|
363
405
|
case "send_message": {
|
|
364
406
|
const input = schemas.send_message.parse(args);
|
|
365
407
|
const result = await client.sendMessage({
|
|
366
|
-
to:
|
|
367
|
-
cc: asArray(input.cc),
|
|
408
|
+
to: input.to,
|
|
368
409
|
subject: input.subject,
|
|
369
410
|
body: input.body,
|
|
370
411
|
priority: input.priority,
|
|
371
412
|
reply_to: input.reply_to ?? null,
|
|
372
|
-
|
|
413
|
+
// Le protocole HTTP et le stockage gardent `thread_title` ; seul l'outil dit `thread_name`.
|
|
414
|
+
thread_title: input.thread_name ?? null,
|
|
373
415
|
thread_description: input.thread_description ?? null,
|
|
374
416
|
});
|
|
375
417
|
const lines = [
|
|
376
418
|
`Message sent: ${result.message_id}`,
|
|
377
419
|
`Thread: ${formatThreadRef(result.thread_title, result.thread_id)}`,
|
|
378
|
-
`Delivered to: ${result.delivered_to
|
|
420
|
+
`Delivered to: ${result.delivered_to}`,
|
|
379
421
|
];
|
|
380
422
|
if (!result.thread_title && !input.reply_to) {
|
|
381
|
-
lines.push("This thread has no name yet —
|
|
423
|
+
lines.push("This thread has no name yet — rename_thread with its thread_id makes it readable for everyone.");
|
|
382
424
|
}
|
|
383
|
-
if (result.
|
|
384
|
-
lines.push(`Warning — never connected to this server, the message will wait in their mailbox
|
|
425
|
+
if (result.unknown_recipient) {
|
|
426
|
+
lines.push(`Warning — ${result.delivered_to} has never connected to this server, the message will wait in their mailbox.`);
|
|
385
427
|
}
|
|
386
428
|
return lines.join("\n");
|
|
387
429
|
}
|
|
@@ -497,10 +539,28 @@ export async function callTool(client, name, rawArgs) {
|
|
|
497
539
|
throw new Error(`Unknown tool: ${name}`);
|
|
498
540
|
}
|
|
499
541
|
}
|
|
500
|
-
function
|
|
501
|
-
|
|
502
|
-
|
|
503
|
-
|
|
542
|
+
async function renameMailbox(client, name, description) {
|
|
543
|
+
const agent = await client.updateProfile({ display_name: name, description });
|
|
544
|
+
return [
|
|
545
|
+
`Mailbox ${agent.id} named "${agent.display_name}".`,
|
|
546
|
+
agent.agent_name ? `The agent name stays "${agent.agent_name}"; both are shown together.` : null,
|
|
547
|
+
]
|
|
548
|
+
.filter(Boolean)
|
|
549
|
+
.join("\n");
|
|
550
|
+
}
|
|
551
|
+
/** `Agent · Boîte` : l'agent dit d'où l'on écrit, la boîte de quoi il est question. */
|
|
552
|
+
function formatAgentNames(agent) {
|
|
553
|
+
return [agent.agent_name, agent.display_name].filter(Boolean).join(" · ");
|
|
554
|
+
}
|
|
555
|
+
async function renameThread(client, threadId, name, description) {
|
|
556
|
+
const thread = await client.setThreadLabel(threadId, { title: name, description });
|
|
557
|
+
return [
|
|
558
|
+
`Thread ${thread.thread_id} is now named "${thread.title}".`,
|
|
559
|
+
thread.description ? `Description: ${thread.description}` : null,
|
|
560
|
+
"Every participant of the thread sees this name.",
|
|
561
|
+
]
|
|
562
|
+
.filter(Boolean)
|
|
563
|
+
.join("\n");
|
|
504
564
|
}
|
|
505
565
|
/** `titre (id)`, ou l'id seul tant que le fil n'a pas été nommé. */
|
|
506
566
|
function formatThreadRef(title, threadId) {
|
|
@@ -523,7 +583,7 @@ function formatSummary(message) {
|
|
|
523
583
|
const priority = message.priority === "normal" ? "" : ` [${message.priority}]`;
|
|
524
584
|
return [
|
|
525
585
|
`${flags} ${message.subject}${priority}`,
|
|
526
|
-
` from ${message.from} to ${message.to
|
|
586
|
+
` from ${message.from} to ${message.to || "—"} · ${message.created_at}`,
|
|
527
587
|
` ${message.preview}`,
|
|
528
588
|
` id ${message.message_id} · thread ${formatThreadRef(message.thread_title, message.thread_id)}`,
|
|
529
589
|
].join("\n");
|
|
@@ -532,8 +592,7 @@ function formatMessage(message) {
|
|
|
532
592
|
const header = [
|
|
533
593
|
`Subject: ${message.subject}`,
|
|
534
594
|
`From: ${message.from}`,
|
|
535
|
-
`To: ${message.to
|
|
536
|
-
message.cc.length ? `Cc: ${message.cc.join(", ")}` : null,
|
|
595
|
+
`To: ${message.to || "—"}`,
|
|
537
596
|
`Date: ${message.created_at}`,
|
|
538
597
|
`Priority: ${message.priority}`,
|
|
539
598
|
`Folder: ${message.folder}${message.read ? "" : " (unread)"}${message.starred ? " ★" : ""}`,
|
package/dist/src/server/app.js
CHANGED
|
@@ -14,15 +14,20 @@ import { logger } from "../logger.js";
|
|
|
14
14
|
const UI_DIR = path.join(path.dirname(fileURLToPath(import.meta.url)), "ui");
|
|
15
15
|
const agentIdSchema = z.string().trim().min(1).max(128);
|
|
16
16
|
const idListSchema = z.array(z.string().trim().min(1)).min(1).max(200);
|
|
17
|
-
|
|
17
|
+
/** Nom et description de la boîte : ce que l'agent pose lui-même sur sa session. */
|
|
18
|
+
const mailboxProfileSchema = z.object({
|
|
18
19
|
display_name: z.string().trim().max(200).nullish(),
|
|
19
20
|
description: z.string().trim().max(2000).nullish(),
|
|
21
|
+
});
|
|
22
|
+
const registerSchema = mailboxProfileSchema.extend({
|
|
23
|
+
/** Identité de l'agent (le projet, typiquement) : vient de la configuration, pas de l'agent. */
|
|
24
|
+
agent_name: z.string().trim().max(200).nullish(),
|
|
25
|
+
agent_description: z.string().trim().max(2000).nullish(),
|
|
20
26
|
/** true = l'adresse doit être inconnue du serveur (allocation d'une boîte neuve). */
|
|
21
27
|
fresh: z.boolean().optional(),
|
|
22
28
|
});
|
|
23
29
|
const sendSchema = z.object({
|
|
24
|
-
to:
|
|
25
|
-
cc: z.union([agentIdSchema, z.array(agentIdSchema)]).optional(),
|
|
30
|
+
to: agentIdSchema,
|
|
26
31
|
subject: z.string().min(1).max(500),
|
|
27
32
|
body: z.string().min(1).max(200_000),
|
|
28
33
|
priority: z.enum(PRIORITIES).optional(),
|
|
@@ -191,16 +196,21 @@ export function createApp({ store, config }) {
|
|
|
191
196
|
}
|
|
192
197
|
const agent = store.ensureAgent(req.agentId, {
|
|
193
198
|
registered: true,
|
|
199
|
+
agent_name: input.agent_name ?? null,
|
|
200
|
+
agent_description: input.agent_description ?? null,
|
|
201
|
+
// Un client antérieur à la séparation agent / boîte n'envoie que ces deux-là.
|
|
194
202
|
display_name: input.display_name ?? null,
|
|
195
203
|
description: input.description ?? null,
|
|
196
204
|
});
|
|
197
205
|
res.json({ agent });
|
|
198
206
|
});
|
|
199
|
-
|
|
200
|
-
|
|
207
|
+
// L'agent ne se voit pas dans son propre annuaire : sa boîte est la seule interdite d'envoi.
|
|
208
|
+
api.get("/agents", (req, res) => {
|
|
209
|
+
res.json({ agents: store.listAgents(req.agentId) });
|
|
201
210
|
});
|
|
211
|
+
// Ne touche qu'à la boîte : l'identité de l'agent ne se renomme pas depuis une session.
|
|
202
212
|
api.patch("/agents/me", (req, res) => {
|
|
203
|
-
const input =
|
|
213
|
+
const input = mailboxProfileSchema.parse(req.body ?? {});
|
|
204
214
|
res.json({
|
|
205
215
|
agent: store.ensureAgent(req.agentId, {
|
|
206
216
|
registered: true,
|
|
@@ -222,8 +232,7 @@ export function createApp({ store, config }) {
|
|
|
222
232
|
const input = sendSchema.parse(req.body ?? {});
|
|
223
233
|
const result = store.sendMessage({
|
|
224
234
|
from: req.agentId,
|
|
225
|
-
to:
|
|
226
|
-
cc: toArray(input.cc),
|
|
235
|
+
to: input.to,
|
|
227
236
|
subject: input.subject,
|
|
228
237
|
body: input.body,
|
|
229
238
|
priority: input.priority,
|
|
@@ -231,7 +240,7 @@ export function createApp({ store, config }) {
|
|
|
231
240
|
thread_title: input.thread_title ?? null,
|
|
232
241
|
thread_description: input.thread_description ?? null,
|
|
233
242
|
});
|
|
234
|
-
logger.info(`message ${result.message_id}: ${req.agentId} -> ${result.delivered_to
|
|
243
|
+
logger.info(`message ${result.message_id}: ${req.agentId} -> ${result.delivered_to}`);
|
|
235
244
|
res.status(201).json(result);
|
|
236
245
|
});
|
|
237
246
|
api.get("/messages", (req, res) => {
|
|
@@ -337,11 +346,6 @@ export function createApp({ store, config }) {
|
|
|
337
346
|
});
|
|
338
347
|
return app;
|
|
339
348
|
}
|
|
340
|
-
function toArray(value) {
|
|
341
|
-
if (value === undefined)
|
|
342
|
-
return [];
|
|
343
|
-
return Array.isArray(value) ? value : [value];
|
|
344
|
-
}
|
|
345
349
|
/**
|
|
346
350
|
* Exige un jeton connu du serveur sur toute requête entrante.
|
|
347
351
|
*
|