agent-relay-server 0.93.0 → 0.93.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/docs/openapi.json CHANGED
@@ -2,7 +2,7 @@
2
2
  "openapi": "3.1.0",
3
3
  "info": {
4
4
  "title": "Agent Relay API",
5
- "version": "0.93.0",
5
+ "version": "0.93.1",
6
6
  "description": "Real-time message bus for inter-agent communication. Agent-first: this spec is designed for machine consumption — agents can self-discover the full API surface via GET /api/spec.",
7
7
  "license": {
8
8
  "name": "MIT",
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "agent-relay-server",
3
- "version": "0.93.0",
3
+ "version": "0.93.1",
4
4
  "description": "Lightweight HTTP message relay for inter-agent communication across machines",
5
5
  "module": "src/index.ts",
6
6
  "type": "module",
@@ -46,7 +46,7 @@ const VALID_ARTIFACT_ENTITY_TYPES = ["message", "task", "recipeRun", "recipeStep
46
46
  export const MESSAGING_TOOLS: ToolDefinition[] = [
47
47
  {
48
48
  name: "relay_send_message",
49
- description: "Send an Agent Relay message. Returns a delivery receipt (delivered/expectReply/recipients): if expectReply is false, no live recipient exists — don't wait for a reply. An ambiguous target is rejected up front. An unknown target is stored for delivery once that id registers (the receipt reports delivered:false with empty recipients and a reason) — never silently dropped.",
49
+ description: "Send an Agent Relay message. Accepts message as an alias for body. Returns a delivery receipt (delivered/expectReply/recipients): if expectReply is false, no live recipient exists — don't wait for a reply. An ambiguous target is rejected up front. An unknown target is stored for delivery once that id registers (the receipt reports delivered:false with empty recipients and a reason) — never silently dropped.",
50
50
  requiredScopes: ["messages:write", "message:send"],
51
51
  inputSchema: {
52
52
  type: "object",
@@ -54,6 +54,7 @@ export const MESSAGING_TOOLS: ToolDefinition[] = [
54
54
  from: { type: "string", description: "Deprecated/optional. Your identity is taken from your auth token; ignored for managed agents. You never need to set this." },
55
55
  to: { type: "string", description: "Target: an agent id, label, name, or a unique id segment (e.g. the number part) — resolved automatically. Or a fan-out selector: tag:, cap:, label:, team:, policy:, or broadcast." },
56
56
  body: { type: "string" },
57
+ message: { type: "string", description: "Alias for body." },
57
58
  kind: { type: "string", enum: ["chat", "channel.event", "task", "pair", "control", "system", "session"] },
58
59
  subject: { type: "string" },
59
60
  channel: { type: "string" },
@@ -64,13 +65,13 @@ export const MESSAGING_TOOLS: ToolDefinition[] = [
64
65
  payload: { type: "object" },
65
66
  meta: { type: "object" },
66
67
  },
67
- required: ["to", "body"],
68
+ required: ["to"],
68
69
  additionalProperties: false,
69
70
  },
70
71
  },
71
72
  {
72
73
  name: "relay_reply",
73
- description: "Reply to an Agent Relay message by id, preserving reply/thread/channel context. Returns a delivery receipt; expectReply:false means the original sender is no longer reachable.",
74
+ description: "Reply to an Agent Relay message by id, preserving reply/thread/channel context. Accepts message as an alias for body. Returns a delivery receipt; expectReply:false means the original sender is no longer reachable.",
74
75
  requiredScopes: ["messages:write", "message:send"],
75
76
  inputSchema: {
76
77
  type: "object",
@@ -78,13 +79,14 @@ export const MESSAGING_TOOLS: ToolDefinition[] = [
78
79
  from: { type: "string", description: "Deprecated/optional. Your identity is taken from your auth token; ignored for managed agents. You never need to set this." },
79
80
  messageId: { type: "integer", minimum: 1 },
80
81
  body: { type: "string" },
82
+ message: { type: "string", description: "Alias for body." },
81
83
  subject: { type: "string" },
82
84
  format: { type: "string", enum: ["text", "markdown", "markdownv2"] },
83
85
  attachments: { type: "array", items: { type: "object" } },
84
86
  payload: { type: "object" },
85
87
  meta: { type: "object" },
86
88
  },
87
- required: ["messageId", "body"],
89
+ required: ["messageId"],
88
90
  additionalProperties: false,
89
91
  },
90
92
  },
@@ -240,7 +242,7 @@ export function relaySendMessage(auth: McpAuthContext, args: Record<string, unkn
240
242
  at: deliveryTime,
241
243
  kind,
242
244
  channel,
243
- body: stringField(args.body, "body", { required: true, maxBytes: MAX_BODY_BYTES }),
245
+ body: messageBody(args),
244
246
  subject: optionalString(args.subject, "subject", 200),
245
247
  claimable,
246
248
  payload,
@@ -258,7 +260,7 @@ export function relaySendMessage(auth: McpAuthContext, args: Record<string, unkn
258
260
  to: stringField(args.to, "to", { required: true, max: 200 }),
259
261
  kind,
260
262
  channel,
261
- body: stringField(args.body, "body", { required: true, maxBytes: MAX_BODY_BYTES }),
263
+ body: messageBody(args),
262
264
  subject: optionalString(args.subject, "subject", 200),
263
265
  claimable,
264
266
  idempotencyKey: optionalString(args.idempotencyKey, "idempotencyKey", 240),
@@ -283,7 +285,7 @@ export function relayReply(auth: McpAuthContext, args: Record<string, unknown>):
283
285
  return runMcpSend(auth, {
284
286
  from: optionalString(args.from, "from", 200) ?? "",
285
287
  to: "",
286
- body: stringField(args.body, "body", { required: true, maxBytes: MAX_BODY_BYTES }),
288
+ body: messageBody(args),
287
289
  subject: optionalString(args.subject, "subject", 200),
288
290
  replyTo: parent.id,
289
291
  attachments,
@@ -292,6 +294,12 @@ export function relayReply(auth: McpAuthContext, args: Record<string, unknown>):
292
294
  });
293
295
  }
294
296
 
297
+ function messageBody(args: Record<string, unknown>): string {
298
+ const value = args.body ?? args.message;
299
+ if (value === undefined || value === null) throw new ValidationError("body (or its alias message) is required");
300
+ return stringField(value, "body", { required: true, maxBytes: MAX_BODY_BYTES });
301
+ }
302
+
295
303
  export function relayGetMessage(args: Record<string, unknown>): Record<string, unknown> {
296
304
  const messageId = positiveId(args.messageId, "messageId");
297
305
  const message = getMessage(messageId);
@@ -2,7 +2,7 @@ import { McpAuthError } from "../mcp-errors";
2
2
  import { authContextFromMcp } from "../services/auth-context";
3
3
  import { ServiceAuthError } from "../services/errors";
4
4
  import { cancelTimer, listTimers, scheduleTimer, type ScheduleTimerInput } from "../services/scheduler";
5
- import type { ScheduledTimer } from "../db";
5
+ import { ValidationError, type ScheduledTimer } from "../db";
6
6
  import type { McpAuthContext, ToolDefinition } from "./types";
7
7
  import { optionalBoolean, optionalPositiveInt, optionalRecord, optionalString, stringField } from "./validation";
8
8
 
@@ -45,14 +45,14 @@ export const SCHEDULER_TOOLS: ToolDefinition[] = [
45
45
  },
46
46
  {
47
47
  name: "relay_cancel_timer",
48
- description: "Cancel one of your durable Relay timers. Admin callers may cancel any timer.",
48
+ description: "Cancel one of your durable Relay timers. Accepts id as an alias for timerId, matching the id returned by relay_schedule_timer. Admin callers may cancel any timer.",
49
49
  requiredScopes: ["schedule:write"],
50
50
  inputSchema: {
51
51
  type: "object",
52
52
  properties: {
53
53
  timerId: { type: "string" },
54
+ id: { type: "string", description: "Alias for timerId (matches the `id` field returned by relay_schedule_timer)." },
54
55
  },
55
- required: ["timerId"],
56
56
  additionalProperties: false,
57
57
  },
58
58
  },
@@ -77,10 +77,16 @@ export function relayListTimers(auth: McpAuthContext, args: Record<string, unkno
77
77
 
78
78
  export function relayCancelTimer(auth: McpAuthContext, args: Record<string, unknown>): Record<string, unknown> {
79
79
  return withAuthErrors(() => ({
80
- timer: serializeTimer(cancelTimer(stringField(args.timerId, "timerId", { required: true, max: 120 }), authContextFromMcp(authContextPayload(auth)))),
80
+ timer: serializeTimer(cancelTimer(timerIdArg(args), authContextFromMcp(authContextPayload(auth)))),
81
81
  }));
82
82
  }
83
83
 
84
+ function timerIdArg(args: Record<string, unknown>): string {
85
+ const value = args.timerId ?? args.id;
86
+ if (value === undefined || value === null) throw new ValidationError("timerId (or its alias id) is required");
87
+ return stringField(value, "timerId", { required: true, max: 120 });
88
+ }
89
+
84
90
  function cleanScheduleInput(args: Record<string, unknown>): ScheduleTimerInput {
85
91
  return {
86
92
  target: optionalString(args.target, "target", 200),