Skip to content
Merged
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
129 changes: 129 additions & 0 deletions docs/internal/USER_MANAGEMENT_API.md
Original file line number Diff line number Diff line change
Expand Up @@ -491,6 +491,135 @@ Revoke one of the authenticated user's tokens. Users can only revoke their own t

---

## Responses API

Routes through the full agent loop — tools, memory, safety, and server-side conversation state are all active. Compatible with any standard OpenAI SDK via `client.responses.create()`.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

medium

The claim that this API is "Compatible with any standard OpenAI SDK via client.responses.create()" is misleading. Official OpenAI SDKs (such as the Python and Node.js libraries) do not have a responses resource or a create method under that name. While the request/response format may be similar to OpenAI's, users will need to use generic HTTP request methods (e.g., client.post) to interact with this specific endpoint.


**Auth:** Any authenticated user (`Authorization: Bearer <token>`)

### POST /v1/responses

Create a response.

**Request body:**

```json
{
"model": "claude-sonnet-4-5-20250514",
"input": "What's a good time to send money to India?",
"stream": true,
"previous_response_id": null
}
```

| Field | Type | Notes |
|-------|------|-------|
| `model` | string | LLM model to use. Pass `"default"` to use the server-configured model |
| `input` | string or array | User message as a string, or a messages array (see below) |
| `stream` | boolean | `true` for SSE, `false` for blocking (120s timeout) |
| `previous_response_id` | string | Pass the previous `id` to continue a conversation thread |
Comment on lines +506 to +520

Copilot AI Apr 14, 2026

Copy link

Choose a reason for hiding this comment

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

The examples/documentation imply callers can choose an arbitrary model (e.g., claude-sonnet-4-5-20250514), but the current POST /v1/responses implementation rejects any model other than "default" with a 400. Please update the request example and model field notes to reflect that only "default" is supported right now (or change the endpoint if model selection is intended).

Copilot uses AI. Check for mistakes.

**Messages array input:** `input` may be passed as an array instead of a string:

```json
{
"model": "default",
"input": [
{ "role": "user", "content": "What is 2+2? Reply with just the number." }
]
}
```

**Response (non-streaming):** `200 OK`

```json
{
"id": "resp_<uuid>",
"object": "response",
"created_at": 1743000000,
"model": "claude-sonnet-4-5-20250514",

Copilot AI Apr 14, 2026

Copy link

Choose a reason for hiding this comment

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

The response example shows "model": "claude-sonnet-4-5-20250514", but responses from this endpoint currently use model: "default" (and the create handler rejects non-default models). Please align the example response model value with actual behavior to avoid confusing SDK users.

Suggested change
"model": "claude-sonnet-4-5-20250514",
"model": "default",

Copilot uses AI. Check for mistakes.
"status": "completed",
"output": [
{
"type": "message",
"id": "msg_<uuid>",
"role": "assistant",
"content": [{ "type": "output_text", "text": "Based on today's rate..." }]
}
],
"usage": {
"input_tokens": 320,
"output_tokens": 95,
"total_tokens": 415
}
}
```

**Streaming:** When `stream: true`, IronClaw returns SSE events:

| Event | Description |
|-------|-------------|
| `response.created` | Response object created, stream begins |
| `response.output_item.added` | New output item started (message or tool call) |
| `response.output_text.delta` | Text chunk |
| `response.output_item.done` | Output item finalized |
| `response.completed` | Full response done |
| `response.failed` | Error or tool approval required |

**Multi-turn:** Pass `previous_response_id` from the previous response's `id` to continue in the same thread. IronClaw decodes the thread UUID statelessly from the response ID — no lookup table required.

**Status values:** `completed` | `failed`

Comment on lines +571 to +572

Copilot AI Apr 14, 2026

Copy link

Choose a reason for hiding this comment

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

status can be in_progress during streaming (the server emits response.created with an in-progress response object), but the docs list only completed | failed. Please include in_progress as a possible status value (at least for streaming events).

Suggested change
**Status values:** `completed` | `failed`
**Status values:** `in_progress` | `completed` | `failed`
For streaming responses, expect `status: "in_progress"` on the initial `response.created` event and until the response reaches a terminal state of `completed` or `failed`.

Copilot uses AI. Check for mistakes.
---

### Structured context

The `input` field accepts a structured `context` object alongside the user message. Use this to pass machine-readable state that the agent should act on, without relying solely on natural language.

**Request:**

```json
{
"model": "claude-sonnet-4-5-20250514",
"input": "Go ahead with the transfer",
"previous_response_id": "resp_...",
"x_context": {
"notification_response": {
"notification_id": "msg_123",
"action": "approved",
"original_signal": "convert_now",
"score": 72,
"rate": 85.42,
"amount_usd": 1000
}
}
}
Comment on lines +575 to +596

Copilot AI Apr 14, 2026

Copy link

Choose a reason for hiding this comment

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

The docs describe a x_context request field that is prepended to the user message and persisted, but the current Responses API request type does not accept/process x_context (unknown JSON fields are ignored and nothing is added to message metadata). Please either remove/mark this section as not yet supported, or implement x_context handling so the described behavior is true.

Copilot uses AI. Check for mistakes.
```

The agent receives the context prepended to the user message:

```
[Context: notification_response — notification_id: msg_123, action: approved,
original_signal: convert_now, score: 72, rate: 85.42, amount_usd: 1000]
Go ahead with the transfer
```

The `context` payload is persisted in message metadata for auditability.
Comment on lines +575 to +607

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

medium

This section describes a "Structured context" feature using an x_context field that is not currently implemented in the backend. The ResponsesRequest struct in src/channels/web/responses_api.rs does not define an x_context field, and the handler does not contain logic to process it or prepend it to the user message as described. Additionally, the text states the context object is accepted within the input field, while the example shows x_context as a top-level field. This section should be removed or updated to reflect the actual capabilities of the API.


---

### GET /v1/responses/{id}

Retrieve a historical response reconstructed from conversation messages in the database. Users can only retrieve their own responses.

**Auth:** Any authenticated user

**Response:** `200 OK` — same shape as the create response object above.

**Errors:** `400` (empty input), `401` (missing or invalid bearer token), `404` (response ID not found or not owned by caller), `500` (internal error)

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

medium

The error list for the GET endpoint is missing the 503 Service Unavailable status code, which is returned by the implementation when the database is not configured (see src/channels/web/responses_api.rs, line 1061). Also, the 400 error on a GET request typically refers to an invalid response ID rather than "empty input."

Suggested change
**Errors:** `400` (empty input), `401` (missing or invalid bearer token), `404` (response ID not found or not owned by caller), `500` (internal error)
Errors: 400 (invalid response ID), 401 (missing or invalid bearer token), 404 (response ID not found or not owned by caller), 503 (database not configured), 500 (internal error)


Comment on lines +617 to +620

Copilot AI Apr 14, 2026

Copy link

Choose a reason for hiding this comment

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

The documented GET errors don’t match the handler behavior: 400 is returned for an invalid response_id format (not “empty input”), and 503 is possible when the database isn’t configured. Also, this endpoint returns OpenAI-style JSON errors ({ "error": { ... } }), which differs from the plain-text ## Error Format section below—please clarify the Responses API error shape here to avoid misleading clients.

Copilot uses AI. Check for mistakes.
---

## Error Format

All error responses return a plain text body with the error message and the corresponding HTTP status code:
Expand Down
Loading