- POST /api/rooms/:id/join + rendezvous_join MCP tool; creator auto-joined - joined_at shown to agents, observer (invite not confirmed yet) and used by the turn indicator; what_you_should_do_next starts with joining - fix: participant list order is now stable (insertion order)
This commit is contained in:
@@ -184,6 +184,13 @@ export function buildRouter(service: RendezvousService, cfg: ServerConfig) {
|
||||
}
|
||||
}
|
||||
|
||||
router.on('POST', '/api/rooms/:id/join', (ctx) => {
|
||||
writeAllowed(ctx);
|
||||
const token = requireToken(ctx);
|
||||
const r = service.join(ctx.params.id, token);
|
||||
sendJson(ctx.res, 200, { joined: true, ...r });
|
||||
});
|
||||
|
||||
router.on('POST', '/api/rooms/:id/messages', (ctx) => {
|
||||
writeAllowed(ctx);
|
||||
const token = requireToken(ctx);
|
||||
|
||||
@@ -65,6 +65,7 @@ You receive one **secret invite URL per participant** plus one **observer URL**
|
||||
|
||||
Authenticate every request with \`Authorization: Bearer <your token>\` (or \`?token=\`). Your token is in your invite URL.
|
||||
|
||||
- \`POST /api/rooms/<room_id>/join\` — **first action**: report you have taken the room into work; the other side (and the human) sees you joined.
|
||||
- \`GET /r/<room>/<your-token>.md\` — compact Markdown state: who you are, goal, messages, open questions, contract, available actions.
|
||||
- \`GET /api/rooms/<room_id>\` — full JSON state, including \`what_you_should_do_next\` — follow it; it tells you exactly what is expected of you now.
|
||||
- \`POST /api/rooms/<room_id>/messages\` \`{"content": "..."}\` — state facts from your side.
|
||||
@@ -180,11 +181,15 @@ export function destroyedPage(): string {
|
||||
export function observerHtmlPage(o: ObserverView, token: string): string {
|
||||
const waiting = new Set(o.turn_waiting_for);
|
||||
const roleList = o.participants
|
||||
.map((p) =>
|
||||
waiting.has(p.role)
|
||||
.map((p) => {
|
||||
const mark = waiting.has(p.role)
|
||||
? `<span class="turn-role" title="the move is expected from this participant">► ${escapeHtml(p.role)}</span>`
|
||||
: escapeHtml(p.role),
|
||||
)
|
||||
: escapeHtml(p.role);
|
||||
const joined = p.joined_at
|
||||
? `<span class="meta">✅ took the room into work ${escapeHtml(p.joined_at)}</span>`
|
||||
: '<span class="meta">⏳ invite not confirmed yet</span>';
|
||||
return `${mark} (${joined})`;
|
||||
})
|
||||
.join(', ');
|
||||
const msgs = o.conversation
|
||||
.map(
|
||||
@@ -303,6 +308,7 @@ The observer URL (${baseUrl}/o/<room>/<observer-token>, also as .md) shows the n
|
||||
## Endpoints (authenticate: Authorization: Bearer <your token> or ?token=)
|
||||
|
||||
- GET ${baseUrl}/create.md — full instructions for agents (start here).
|
||||
- POST ${baseUrl}/api/rooms/<room_id>/join — FIRST ACTION after opening your invite: report you have taken the room into work (idempotent). The other side and the observer see your joined status.
|
||||
- GET ${baseUrl}/r/<room>/<your-token>.md — compact Markdown room state: who you are, goal, messages, open questions, contract, available actions.
|
||||
- GET ${baseUrl}/api/rooms/<room_id> — full JSON state incl. what_you_should_do_next and available_actions.
|
||||
- POST ${baseUrl}/api/rooms/<room_id>/messages — {"content":"verified facts / answers"}.
|
||||
|
||||
@@ -119,6 +119,14 @@ test('HTTP: cannot read room by id without token; unknown routes 404; human page
|
||||
// observer HTML highlights whose turn it is after a blocking question appears
|
||||
const pidA = created.participants[0].id;
|
||||
const tokB = created.invite_urls[1].split('/').pop();
|
||||
// before join: observer turn waits on B joining
|
||||
const obsHtml0 = await (await fetch(created.observer_url)).text();
|
||||
assert.match(obsHtml0, /invite not confirmed/);
|
||||
// B reports taking the room into work
|
||||
const j = await (await fetch(`${baseUrl}/api/rooms/${created.room_id}/join`, {
|
||||
method: 'POST', headers: { authorization: `Bearer ${tokB}` },
|
||||
})).json();
|
||||
assert.equal((j as any).joined, true);
|
||||
await fetch(`${baseUrl}/api/rooms/${created.room_id}/questions`, {
|
||||
method: 'POST', headers: { authorization: `Bearer ${tokB}`, 'content-type': 'application/json' },
|
||||
body: JSON.stringify({ question: 'verify X on your side', blocking: true, addressed_to_participant_id: pidA }),
|
||||
|
||||
Reference in New Issue
Block a user