be: POST /roster/assistant/propose endpoint + in-memory session store #1212

Closed
opened 2026-05-15 17:02:14 +00:00 by architect · 2 comments
Collaborator

Context

Part of the Agents Roster AI Assistant feature. The FE sidebar sends user messages and receives structured ProposalEnvelopes. This ticket is the HTTP surface and the session lifecycle — the actual Claude call and prompt assembly live in a separate ticket so this can land in parallel with the prompt work.

Scope

Endpoint

POST /roster/assistant/propose

Request:

{
  session_id?: string;         // omitted on first call; server assigns
  message: string;             // operator's free-text input
  current_roster?: AgentConfig[]; // optional, for context; not used in v1 since scope is new-fleet only
}

Response: ProposalEnvelope (from #1210)

Session store

In-memory map keyed by session_id. Holds:

  • conversation history (user messages + prior proposals)
  • refinements_used counter
  • last catalog_hash shown to the model
  • created_at / last_touched_at for GC

GC policy: drop sessions idle > 1 hour. No persistence in v1.

Rate limiting

  • Soft cap: 20 refinements per session. Past the cap, still serve but include a soft_cap_exceeded: true flag in the envelope so FE can warn.
  • Hard cap: none in v1.

Error handling

  • Validate message length (reject > 4000 chars with 400)
  • If the prompt-builder call fails or returns malformed JSON, return 502 with a structured error body — do NOT mutate session history on failure
  • If session_id not found, return 404 (FE should drop the id and start fresh)

Deliverables

  • Route handler + request/response types from #1210
  • In-memory session store with GC
  • Refinement counter + soft cap flag
  • Integration tests: new session, refinement (parent_proposal_id wired), unknown session 404, oversized message 400, malformed model output 502
  • Hands off prompt construction + model call to a buildAndCallProposer(history, catalog) injection point — that's a separate ticket's responsibility

Notes for implementer

The Claude call is NOT in scope for this ticket. Mock the prompt-builder behind a function interface so tests can run without a real model call, and so the prompt ticket can be landed in parallel.


Depends on: #1210 (proposal types)
Depended on by: assistant prompt ticket, FE sidebar ticket

## Context Part of the **Agents Roster AI Assistant** feature. The FE sidebar sends user messages and receives structured `ProposalEnvelope`s. This ticket is the HTTP surface and the session lifecycle — the actual Claude call and prompt assembly live in a separate ticket so this can land in parallel with the prompt work. ## Scope ### Endpoint `POST /roster/assistant/propose` **Request**: ```ts { session_id?: string; // omitted on first call; server assigns message: string; // operator's free-text input current_roster?: AgentConfig[]; // optional, for context; not used in v1 since scope is new-fleet only } ``` **Response**: `ProposalEnvelope` (from #1210) ### Session store In-memory map keyed by `session_id`. Holds: - conversation history (user messages + prior proposals) - `refinements_used` counter - last `catalog_hash` shown to the model - created_at / last_touched_at for GC GC policy: drop sessions idle > 1 hour. No persistence in v1. ### Rate limiting - Soft cap: 20 refinements per session. Past the cap, still serve but include a `soft_cap_exceeded: true` flag in the envelope so FE can warn. - Hard cap: none in v1. ### Error handling - Validate `message` length (reject > 4000 chars with 400) - If the prompt-builder call fails or returns malformed JSON, return 502 with a structured error body — do NOT mutate session history on failure - If `session_id` not found, return 404 (FE should drop the id and start fresh) ## Deliverables - [ ] Route handler + request/response types from #1210 - [ ] In-memory session store with GC - [ ] Refinement counter + soft cap flag - [ ] Integration tests: new session, refinement (parent_proposal_id wired), unknown session 404, oversized message 400, malformed model output 502 - [ ] Hands off prompt construction + model call to a `buildAndCallProposer(history, catalog)` injection point — that's a separate ticket's responsibility ## Notes for implementer The Claude call is **NOT** in scope for this ticket. Mock the prompt-builder behind a function interface so tests can run without a real model call, and so the prompt ticket can be landed in parallel. --- **Depends on**: #1210 (proposal types) **Depended on by**: assistant prompt ticket, FE sidebar ticket
Author
Collaborator

🤖 Auto-assigned to code-lead (heuristic: area:agents → code-lead (architecture-touching)). Reply /unassign to reroute.

🤖 Auto-assigned to **code-lead** (heuristic: area:agents → code-lead (architecture-touching)). Reply `/unassign` to reroute.
Collaborator

🦵 @charles kicked the queue — re-running implement on @code-lead.

🦵 @charles kicked the queue — re-running implement on @code-lead.
Sign in to join this conversation.
No milestone
No project
No assignees
2 participants
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set.

Reference
charles/agent-hooks#1212
No description provided.