Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions docs-generator.json
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,8 @@
{ "path": "src/routes/inbox.js", "extractor": "rest-api", "provides": "Message send, pull, ack, nack, reply, status, inbox stats endpoints" },
{ "path": "src/routes/groups.js", "extractor": "rest-api", "provides": "Group creation, membership, messaging, join/leave endpoints" },
{ "path": "src/routes/outbox.js", "extractor": "rest-api", "provides": "Outbound email via Mailgun — domain config, send, message queries, webhooks" },
{ "path": "src/routes/round-tables.js", "extractor": "rest-api", "provides": "Round Table endpoints — create, list, get, speak, resolve ephemeral multi-agent deliberation sessions" },
{ "path": "src/services/round-table.service.js", "extractor": "generic", "provides": "Round Table service — enrollment, expiry, notifications, purge logic" },
{ "path": "src/routes/discovery.js", "extractor": "rest-api", "provides": "Public key directory (.well-known/agent-keys.json) and DID document endpoints" },
{ "path": "src/middleware/auth.js", "extractor": "generic", "provides": "Authentication model: HTTP Signatures, API keys, DID:web federation, enrollment tokens" },
{ "path": "src/services/agent.service.js", "extractor": "generic", "provides": "Agent lifecycle: registration modes, approval workflow, key rotation" },
Expand Down
216 changes: 215 additions & 1 deletion docs/API-REFERENCE.md
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
<!-- Generated: 2026-02-26T00:00:00Z -->
<!-- Generated: 2026-03-01T00:00:00Z -->

# Agent Dispatch (ADMP) API Reference

Expand All @@ -25,6 +25,7 @@
- [Key Rotation](#key-rotation)
- [Inbox: Message Operations](#inbox-message-operations)
- [Groups](#groups)
- [Round Tables](#round-tables)
- [Outbox (Email)](#outbox-email)
- [Tenants](#tenants)
- [Admin: Approval Workflow](#admin-approval-workflow)
Expand Down Expand Up @@ -899,6 +900,219 @@ List groups the agent belongs to.

---

## Round Tables

Ephemeral multi-agent deliberation sessions. A facilitator opens a session with a topic, goal, and participant list. Participants speak into a shared thread. The facilitator closes with an outcome. Sessions are time-bounded and backed by the ADMP Groups API for multicast delivery.

**Roles:**
- **Facilitator** — the agent that creates the session. Can resolve it. Cannot be listed as a participant. Receives expiry notifications.
- **Participant** — an enrolled agent. Can speak and read the session. Receives invite and expiry notifications.

**Statuses:** `open` → `resolved` (facilitator called resolve) or `expired` (timeout reached)

---

### POST /api/round-tables

Create a new Round Table session. The calling agent becomes the facilitator.

**Auth:** Agent auth (HTTP Signature or API Key)

**Request body:**

| Field | Type | Required | Description |
|-------|------|----------|-------------|
| `topic` | string | Yes | Session topic. Max 500 characters. |
| `goal` | string | Yes | Desired outcome. Max 500 characters. |
| `participants` | string[] | Yes | List of participant agent IDs. Max 20. Duplicates deduplicated. Facilitator must not be included. |
| `timeout_minutes` | integer | No | Auto-expire after N minutes. Must be an integer between 1 and 10080 (7 days). Default: 30. |

**Response 201:**
```json
{
"id": "rt_abc123def456",
"topic": "Q2 roadmap priorities",
"goal": "Reach consensus on top 3 features",
"facilitator": "orchestrator-agent",
"participants": ["analyst-agent", "planner-agent"],
"group_id": "group://rt_abc123def456",
"status": "open",
"thread": [],
"outcome": null,
"created_at": "2026-03-01T14:00:00.000Z",
"expires_at": "2026-03-01T14:30:00.000Z"
}
```

When some participants cannot be enrolled (e.g. unregistered agent IDs), `excluded_participants` is included:

```json
{
"id": "rt_abc123def456",
"participants": ["analyst-agent"],
"excluded_participants": ["unknown-agent"],
...
}
```

`excluded_participants` is only present at create time when non-empty. It does not appear in GET responses.

Each enrolled participant receives a `work_order` message in their ADMP inbox with the session details and instructions.

**Response 400:**
```json
{"error": "FACILITATOR_IN_PARTICIPANTS", "message": "facilitator cannot be listed as a participant"}
```

```json
{"error": "CREATE_ROUND_TABLE_FAILED", "message": "No participants could be enrolled; round table not created"}
```

---

### GET /api/round-tables

List Round Tables where the caller is the facilitator or an enrolled participant.

**Auth:** Agent auth

**Query parameters:**
- `status` — Filter by status: `open`, `resolved`, `expired`

**Response 200:**
```json
{
"round_tables": [
{
"id": "rt_abc123def456",
"topic": "Q2 roadmap priorities",
"status": "open",
"facilitator": "orchestrator-agent",
"participants": ["analyst-agent", "planner-agent"],
"expires_at": "2026-03-01T14:30:00.000Z",
"created_at": "2026-03-01T14:00:00.000Z"
}
],
"count": 1
}
```

---

### GET /api/round-tables/:id

Get full Round Table session including the message thread.

**Auth:** Agent auth (facilitator or enrolled participant only)

**Path parameters:**
- `id` — Round Table ID (e.g., `rt_abc123def456`)

**Response 200:** Full session record including `thread[]`

```json
{
"id": "rt_abc123def456",
"topic": "Q2 roadmap priorities",
"goal": "Reach consensus on top 3 features",
"facilitator": "orchestrator-agent",
"participants": ["analyst-agent", "planner-agent"],
"group_id": "group://rt_abc123def456",
"status": "open",
"thread": [
{
"id": "uuid",
"from": "analyst-agent",
"message": "I think we should prioritize the auth improvements.",
"timestamp": "2026-03-01T14:05:00.000Z"
}
],
"outcome": null,
"created_at": "2026-03-01T14:00:00.000Z",
"expires_at": "2026-03-01T14:30:00.000Z"
}
```

**Response 403:**
```json
{"error": "GET_ROUND_TABLE_FAILED", "message": "Not a participant of this Round Table"}
```

---

### POST /api/round-tables/:id/speak

Add a message to the Round Table thread. The facilitator and enrolled participants can speak.

**Auth:** Agent auth (enrolled participant only)

**Request body:**

| Field | Type | Required | Description |
|-------|------|----------|-------------|
| `message` | string | Yes | Message content. Max 10,000 characters. |

**Response 201:**
```json
{
"thread_entry_id": "uuid",
"thread_length": 3
}
```

The message is also multicast to all participants via the backing ADMP group.

**Response 403:**
```json
{"error": "SPEAK_FAILED", "message": "Not a participant of this Round Table"}
```

**Response 409:**
```json
{"error": "SPEAK_FAILED", "message": "Round table is already resolved"}
```

```json
{"error": "SPEAK_FAILED", "message": "Round Table thread has reached the maximum of 200 entries"}
```
Comment on lines +1055 to +1077

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Missing Response 400 examples for validation errors:

  • INVALID_MESSAGE when message is missing/empty
  • MESSAGE_TOO_LONG when message exceeds 10000 chars


---

### POST /api/round-tables/:id/resolve

Close the Round Table with an outcome. Facilitator only.

Sends the resolution to all participants via the backing group, then deletes the group. The session record is retained with `status: "resolved"`.

**Auth:** Agent auth (facilitator only)

**Request body:**

| Field | Type | Required | Description |
|-------|------|----------|-------------|
| `outcome` | string | Yes | Summary of what was decided. Max 2,000 characters. |
| `decision` | any | No | Structured decision payload (stored with session). Defaults to `"approved"`. |

**Response 200:** Updated session record with `status: "resolved"`, `outcome`, `decision`, and `resolved_at`.

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Missing Response 400 examples for validation errors:

  • INVALID_OUTCOME when outcome is missing/empty
  • OUTCOME_TOO_LONG when outcome exceeds 2000 chars


```json
{
"id": "rt_abc123def456",
"status": "resolved",
"outcome": "We will prioritize auth improvements, then the CLI, then the SDK.",
"decision": "approved",
"resolved_at": "2026-03-01T14:20:00.000Z",
...
}
```

**Response 403:**
```json
{"error": "RESOLVE_FAILED", "message": "Only the facilitator can resolve a Round Table"}
```

---

## Outbox (Email)

### POST /api/agents/:agentId/outbox/domain
Expand Down
23 changes: 22 additions & 1 deletion docs/ERROR-CODES.md
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
<!-- Generated: 2026-02-26T00:00:00Z -->
<!-- Generated: 2026-03-01T00:00:00Z -->
<!-- Source: Extracted from Agent Dispatch (ADMP) source files -->

# ADMP Error Codes Reference
Expand All @@ -13,6 +13,7 @@ Complete reference of all error codes returned by the Agent Dispatch Messaging P
- [Agent Errors](#agent-errors)
- [Message and Inbox Errors](#message-and-inbox-errors)
- [Group Errors](#group-errors)
- [Round Table Errors](#round-table-errors)
- [Outbox (Email) Errors](#outbox-email-errors)
- [Tenant Errors](#tenant-errors)
- [System Errors](#system-errors)
Expand Down Expand Up @@ -116,6 +117,26 @@ Complete reference of all error codes returned by the Agent Dispatch Messaging P

---

## Round Table Errors

| Code | HTTP | Retryable | Description | Hint |
|------|------|-----------|-------------|------|
| `INVALID_TOPIC` | 400 | No | topic is missing or empty | Provide a non-empty string of at most 500 characters |
| `TOPIC_TOO_LONG` | 400 | No | topic exceeds 500 characters | Shorten the topic |
| `INVALID_GOAL` | 400 | No | goal is missing or empty | Provide a non-empty string of at most 500 characters |
| `GOAL_TOO_LONG` | 400 | No | goal exceeds 500 characters | Shorten the goal |
| `INVALID_PARTICIPANTS` | 400 | No | participants is missing or not a non-empty array | Provide at least one participant agent ID |
| `INVALID_PARTICIPANT_ID` | 400 | No | A participant entry is not a valid string or exceeds 255 chars | Each participant must be a registered agent ID |
| `INVALID_TIMEOUT` | 400 | No | timeout_minutes is not an integer | Must be an integer between 1 and 10080 (7 days) |
| `FACILITATOR_IN_PARTICIPANTS` | 400 | No | The calling agent (facilitator) is listed as a participant | Remove the facilitator's own agent ID from participants |
| `CREATE_ROUND_TABLE_FAILED` | 400 | No | Round Table creation failed | Most commonly: no participants could be enrolled (all provided IDs are unregistered). The backing group is cleaned up automatically. |
| `GET_ROUND_TABLE_FAILED` | 403/404 | No | Session not found or caller is not a participant | Verify the session ID. Only the facilitator and enrolled participants can read a session. |
| `SPEAK_FAILED` | 403/404/409 | No | Cannot speak into session | 403: caller is not an enrolled participant. 404: session not found. 409: session is resolved/expired, or thread has reached the 200-entry limit. |
| `RESOLVE_FAILED` | 400/403/404/409 | No | Cannot resolve session | 400: outcome is missing. 403: caller is not the facilitator. 404: session not found. 409: session is already resolved or expired. |
| `LIST_ROUND_TABLES_FAILED` | 500 | Yes | Transient error listing Round Tables | Retry with backoff |

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Missing 4 validation error codes used in src/routes/round-tables.js:

  • INVALID_MESSAGE (line 103) - message required for speak endpoint
  • MESSAGE_TOO_LONG (line 106) - message max 10000 chars
  • INVALID_OUTCOME (line 129) - outcome required for resolve endpoint
  • OUTCOME_TOO_LONG (line 132) - outcome max 2000 chars


---

## Outbox (Email) Errors

| Code | HTTP | Retryable | Description | Hint |
Expand Down
61 changes: 33 additions & 28 deletions llms.txt
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
# Agent Dispatch (ADMP)
<!-- Generated: 2026-02-26T00:00:00Z -->
<!-- Generated: 2026-03-01T00:00:00Z -->

> Universal inbox for autonomous AI agents — at-least-once delivery, Ed25519 auth, DID federation

Expand Down Expand Up @@ -27,20 +27,10 @@ Required fields: version, from, to, subject, timestamp.
`from`/`to` accept: bare agent IDs, `agent://` URIs, or `did:seed:` DIDs.

```json
{
"version": "1.0",
"id": "uuid",
"type": "task.request",
"from": "sender-id",
"to": "recipient-id",
"subject": "create_user",
"correlation_id": "c-12345",
"headers": {"priority": "high"},
"body": {},
"ttl_sec": 86400,
"timestamp": "2025-10-22T17:30:00Z",
"signature": {"alg": "ed25519", "kid": "sender-id", "sig": "base64..."}
}
{"version":"1.0","id":"uuid","type":"task.request","from":"sender-id","to":"recipient-id",
"subject":"create_user","correlation_id":"c-12345","headers":{"priority":"high"},
"body":{},"ttl_sec":86400,"timestamp":"2025-10-22T17:30:00Z",
"signature":{"alg":"ed25519","kid":"sender-id","sig":"base64..."}}
```

Envelope signing base: `timestamp\nsha256(body)\nfrom\nto\ncorrelation_id`
Expand Down Expand Up @@ -125,6 +115,17 @@ GET /api/groups/:groupId/messages History (?limit=50)
GET /api/agents/:agentId/groups Agent's groups [HTTP Sig]
```

### Round Tables [Agent Auth]

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P1 Badge Reduce llms.txt to satisfy maxLines constraint

This added Round Tables block pushes llms.txt to 269 lines, which exceeds the configured maxLines: 250 budget in docs-generator.json; if downstream generation/validation enforces that setting, the file will either fail checks or be truncated, making part of this update unusable to agent consumers.

Useful? React with 👍 / 👎.

```
POST /api/round-tables Create (body: {topic, goal, participants[], timeout_minutes?})
GET /api/round-tables List mine (?status=open|resolved|expired)
GET /api/round-tables/:id Get (facilitator or participant only)
POST /api/round-tables/:id/speak Speak (body: {message}) [facilitator or participant]
POST /api/round-tables/:id/resolve Resolve (body: {outcome, decision?}) [facilitator only]
```
Limits: topic/goal≤500, message≤10000, outcome≤2000, timeout_minutes int 1–10080 (default 30), max 20 participants.
On expiry: notification (body={reason:"timeout"}) sent to facilitator + all participants. Facilitator gets self-addressed copy.

### Outbox / Email [Agent Auth]
```
POST /api/agents/:agentId/outbox/domain Set domain (body: {domain})
Expand Down Expand Up @@ -153,20 +154,13 @@ GET /api/stats System statistics [API Key]
All commands support `--json` for machine-readable output.

```
admp init Interactive config wizard
admp config show | set <key> <value> Show/set config
admp init | config show | config set <key> <val>
admp register [--name] [--seed <hex>] Register new agent
admp agent get View agent details
admp heartbeat [--metadata <json>] Send keepalive
admp rotate-key [--seed <hex>] Rotate signing key
admp send --to <id> --subject <s> --body <json|@file> Send message
admp pull [--timeout <sec>] Pull next message (max 300s)
admp ack <id> [--result <json>] Acknowledge
admp nack <id> [--extend] [--requeue] Reject/defer
admp reply <id> --subject <s> --body <json> Correlated reply
admp status <id> Delivery status
admp inbox stats Queue counts
admp webhook set --url <u> --secret <s> | get | delete Webhook config
admp agent get | heartbeat | rotate-key [--seed]
admp send --to <id> --subject <s> --body <json|@file>
admp pull [--timeout <sec>] | ack <id> | nack <id> | reply <id> --subject <s> --body <json>
admp status <id> | inbox stats
admp webhook set --url <u> --secret <s> | get | delete
admp groups create --name <n> --access <type> Create group
admp groups list | join <id> [--key] | leave <id> Group membership
admp groups send <id> --subject <s> --body <json> Broadcast to group
Expand Down Expand Up @@ -215,6 +209,7 @@ File: `~/.admp/config.json` (mode 0600)
| `REGISTRATION_POLICY` | `open` | `open` or `approval_required` |
| `MAILGUN_API_KEY` | _(none)_ | Outbound email (secret) |
| `DID_WEB_ALLOWED_DOMAINS` | _(none)_ | Comma-separated DID:web allowlist |
| `ROUND_TABLE_PURGE_TTL_MS` | `604800000` (7d) | Purge TTL for resolved/expired Round Tables |

## Error Codes

Expand All @@ -237,5 +232,15 @@ Format: `{"error": "CODE", "message": "description"}`
| `SEND_FAILED` | 400 | Yes | Message or email send failed |
| `NOT_FOUND` | 404 | No | Endpoint does not exist |
| `INTERNAL_ERROR` | 500 | Yes | Server error (backoff: 1s, 2s, 4s, 8s, 16s, 30s cap) |
| `INVALID_TOPIC / TOPIC_TOO_LONG` | 400 | No | topic missing, empty, or > 500 chars |
| `INVALID_GOAL / GOAL_TOO_LONG` | 400 | No | goal missing, empty, or > 500 chars |
| `INVALID_PARTICIPANTS / INVALID_PARTICIPANT_ID` | 400 | No | participants missing, empty, or IDs invalid |
| `INVALID_TIMEOUT` | 400 | No | timeout_minutes must be an integer (1–10080) |
| `FACILITATOR_IN_PARTICIPANTS` | 400 | No | facilitator cannot be listed as a participant |
| `CREATE_ROUND_TABLE_FAILED` | 400 | No | Round Table creation failed (e.g. zero enrollment) |
| `GET_ROUND_TABLE_FAILED` | 403/404 | No | Not a participant, or session not found |
| `SPEAK_FAILED` | 403/404/409 | No | Not a participant / not found / thread full (200 entries) |
| `RESOLVE_FAILED` | 400/403/404/409 | No | Bad request / not facilitator / not found / already closed |
| `LIST_ROUND_TABLES_FAILED` | 500 | Yes | Transient storage error listing sessions |

Full error reference: docs/ERROR-CODES.md