Responses and streaming

6.1 Request

POST /lmsp/v1/responses
Authorization: Bearer <token>
Content-Type: application/json
Idempotency-Key: 01J8M5T7Z2K4N6Q8S0V3X5B9DG
LMSP-Version: 1.0
{
  "model": "qwen3:14b-q4_k_m",
  "input": [
    {
      "type": "message",
      "role": "user",
      "content": [
        {
          "type": "input_text",
          "text": "Describe a local model service in one sentence."
        }
      ]
    }
  ],
  "stream": false,
  "max_output_tokens": 512,
  "temperature": 0.7,
  "response_format": {
    "type": "text"
  },
  "store": true
}

The core protocol uses a Responses-style input and output structure instead of a plain list of message strings, so that a single request shape can carry:

  • multi-turn messages;
  • text, images, audio and files;
  • tool calls and tool results;
  • structured output;
  • reasoning summaries;
  • multimodal output.

LMSP 1.0 defines text content only. Image, audio and file content types are reserved for later versions.

Field Required Meaning
model Yes Id of the model to use.
input Yes Array of input items. A message item has a role (system, user or assistant) and a content array of parts, such as input_text. Tool use adds function_call and function_call_output items (section 6.5).
stream No true to receive server-sent events. Defaults to false.
max_output_tokens No Upper bound on the number of generated tokens.
temperature No Sampling temperature.
response_format No {"type": "text"} (the default), or {"type": "json_schema", "json_schema": {"name": "...", "schema": {...}}} for structured output. Needs the structured_output capability.
tools, tool_choice No Function tools the model may call (section 6.5). Needs the tools capability.
store No Asks the service to keep the response, so it can be retrieved later and used as previous_response_id. Defaults to false. Ignored by services without the conversations capability.
previous_response_id No Continues from a stored response. Needs the conversations capability.
extensions No Private extensions (section 9.1).

A request that needs a capability the model does not have is rejected with 400 and unsupported_capability. A request that does not fit in the context window is rejected with 400 and context_length_exceeded.

A service that can store conversations MAY also support previous_response_id. Otherwise every request MUST carry the full context. A service MUST NOT rely on the HTTP connection to hold conversation state.

6.2 Synchronous response

When stream is false, the service returns 200 OK with a response object after generation has finished.

{
  "id": "resp_01J8M6Q4W2T7N5R3V9X1Z8B0DF",
  "object": "response",
  "created_at": 1794200000,
  "status": "completed",
  "model": "qwen3:14b-q4_k_m",
  "output": [
    {
      "id": "msg_01J8M6Q4W5C8H2K9P3S7Y1A6ZE",
      "type": "message",
      "role": "assistant",
      "content": [
        {
          "type": "output_text",
          "text": "A local model service is a resident interface layer that discovers, manages and calls models on the user's own device."
        }
      ]
    }
  ],
  "usage": {
    "input_tokens": 28,
    "output_tokens": 31,
    "total_tokens": 59
  },
  "error": null,
  "incomplete_details": null
}
Field Meaning
id Response identifier, such as resp_....
object Always "response".
created_at Creation time, in seconds since the Unix epoch.
status in_progress, completed, incomplete, failed or cancelled. A synchronous response is returned in a final status.
model Id of the model that produced the response.
output Array of output items.
usage Token counts: input_tokens, output_tokens and total_tokens.
error null, or a problem object (section 9.3) when status is failed.
incomplete_details null, or an object with a reason such as max_output_tokens when status is incomplete.

Output item types:

Item type Shape
message id, role (assistant) and content, an array of output_text parts that each have a text.
function_call id, call_id, name and arguments, a JSON-encoded string.
reasoning id and summary, an array of summary_text parts that each have a text.

If generation fails, a synchronous request is answered with an error status and a problem document (section 9.3), not with a response object. The failed status appears in streams, tasks and stored responses.

GET /lmsp/v1/responses/{response_id} returns a response that was stored with store: true. It is optional and needs the conversations capability. An unknown id gives 404 with response_not_found.

6.3 Streaming

To stream, set stream in the request:

{
  "stream": true
}

The service answers 200 OK with Content-Type: text/event-stream and sends semantic events. Each event has an id, an event name and a JSON data object:

id: 1
event: response.created
data: {"response_id":"resp_01J8M6Q4W2T7N5R3V9X1Z8B0DF","status":"in_progress"}

id: 2
event: response.output_item.added
data: {"response_id":"resp_01J8M6Q4W2T7N5R3V9X1Z8B0DF","output_index":0,"item":{"id":"msg_01J8M6Q4W5C8H2K9P3S7Y1A6ZE","type":"message","role":"assistant","content":[]}}

id: 3
event: response.output_text.delta
data: {"response_id":"resp_01J8M6Q4W2T7N5R3V9X1Z8B0DF","item_id":"msg_01J8M6Q4W5C8H2K9P3S7Y1A6ZE","delta":"A local model "}

id: 4
event: response.output_text.delta
data: {"response_id":"resp_01J8M6Q4W2T7N5R3V9X1Z8B0DF","item_id":"msg_01J8M6Q4W5C8H2K9P3S7Y1A6ZE","delta":"service is a resident interface layer."}

id: 5
event: response.output_item.done
data: {"response_id":"resp_01J8M6Q4W2T7N5R3V9X1Z8B0DF","output_index":0,"item":{"id":"msg_01J8M6Q4W5C8H2K9P3S7Y1A6ZE","type":"message","role":"assistant","content":[{"type":"output_text","text":"A local model service is a resident interface layer."}]}}

id: 6
event: response.completed
data: {"response_id":"resp_01J8M6Q4W2T7N5R3V9X1Z8B0DF","status":"completed","usage":{"input_tokens":28,"output_tokens":12,"total_tokens":40}}

At least these events are defined:

Event Meaning Data fields
response.created The response was created. response_id, status (in_progress)
response.output_item.added A new output item started. response_id, output_index, item
response.output_text.delta Text was appended to a message item. response_id, item_id, delta
response.output_item.done An output item is complete. response_id, output_index, item
response.completed The response finished. Final event. response_id, status, usage
response.incomplete Generation stopped early, for example at the token limit. Final event. response_id, status, incomplete_details, usage
response.failed Generation failed. Final event. response_id, status, error
response.cancelled The response was cancelled. Final event. response_id, status
error A problem that is not tied to one response, after which the stream cannot continue. error, a problem object

A service closes the stream after a final event or an error event.

Services MAY send additional events, for example for tool-call arguments, images, audio and structured JSON deltas. Clients MUST ignore event types they do not know.

If the client closes the connection of a streaming request, the service SHOULD stop generating.

6.4 Event ids and reconnection

The id of an event MUST be an integer sequence number that is strictly increasing within the response, starting at 1.

After a dropped connection, a client resumes by sending the last id it received. It does this with a header:

Last-Event-ID: 2

or with a query parameter:

GET /lmsp/v1/tasks/{task_id}/events?after=2

Both go to the events endpoint of a task (section 7.4). The service replays only the events whose sequence number is greater than 2. If both are present, after wins.

If the requested events are older than the retention period, the service answers 410 Gone with the error event_history_expired. The client then fetches the final result instead, with GET /lmsp/v1/tasks/{task_id}.

A response streamed directly from POST /lmsp/v1/responses belongs to that HTTP connection and cannot be resumed. A client that needs resumable output SHOULD create a task and follow its events.

6.5 Tool calls

LMSP 1.0 defines function tools that the client executes. The service does not run tools itself. The tools:execute scope is reserved for extensions that do (section 10.3).

First, the client lists the tools. Each entry has type set to function, a name, a description and parameters, a JSON Schema object. tool_choice is auto (the default), none, required, or {"type": "function", "name": "get_weather"}.

{
  "model": "qwen3:14b-q4_k_m",
  "input": [
    {
      "type": "message",
      "role": "user",
      "content": [
        {
          "type": "input_text",
          "text": "What is the weather in Hangzhou?"
        }
      ]
    }
  ],
  "tools": [
    {
      "type": "function",
      "name": "get_weather",
      "description": "Get the current weather for a city.",
      "parameters": {
        "type": "object",
        "properties": {
          "city": { "type": "string" }
        },
        "required": ["city"]
      }
    }
  ],
  "tool_choice": "auto"
}

When the model decides to call a tool, the response contains a function_call item. Its arguments are a JSON-encoded string. In a stream, the item arrives complete in response.output_item.done.

{
  "id": "resp_01J8M7B3N6Q9T2V5X8Z1C4D7FH",
  "object": "response",
  "created_at": 1794200050,
  "status": "completed",
  "model": "qwen3:14b-q4_k_m",
  "output": [
    {
      "id": "fc_01J8M7B3N8R1S4W7Y0A3E6G9JK",
      "type": "function_call",
      "call_id": "call_01J8M7B3N9T2V5X8Z1C4D7F0HM",
      "name": "get_weather",
      "arguments": "{\"city\":\"Hangzhou\"}"
    }
  ],
  "usage": {
    "input_tokens": 74,
    "output_tokens": 18,
    "total_tokens": 92
  },
  "error": null,
  "incomplete_details": null
}

The client runs the tool, then sends a new request that carries the full context: the earlier input items, the function_call item as received, and a function_call_output item with the same call_id. Its output is a string, usually JSON-encoded.

{
  "type": "function_call_output",
  "call_id": "call_01J8M7B3N9T2V5X8Z1C4D7F0HM",
  "output": "{\"temperature_c\":17,\"condition\":\"light rain\"}"
}