Skip to content

Commit eae833b

Browse files
authored
docs for ask streaming api (#2018)
* docs for ask streaming api * cleanup
1 parent c6c5d68 commit eae833b

File tree

1 file changed

+336
-0
lines changed

1 file changed

+336
-0
lines changed

docs/configuration/holmesgpt/holmes-chat-api.rst

Lines changed: 336 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -198,3 +198,339 @@ If ``cluster_id`` is not provided in the request, Holmes will attempt to determi
198198
3. If only one cluster is connected to the account, use that cluster.
199199

200200
If none of these methods succeed and multiple clusters are connected, the API will return an error listing the available clusters.
201+
202+
203+
Streaming (SSE) Mode
204+
---------------------
205+
206+
The same endpoint supports streaming responses via `Server-Sent Events (SSE) <https://developer.mozilla.org/en-US/docs/Web/API/Server-sent_events>`_.
207+
Instead of waiting for the full analysis, you receive a real-time stream of events as Holmes investigates — including tool calls, intermediate AI messages, and the final answer.
208+
209+
To enable streaming, set ``stream`` to ``true`` in the request body. All other parameters remain the same.
210+
211+
Example Streaming Request
212+
^^^^^^^^^^^^^^^^^^^^^^^^^
213+
214+
.. code-block:: bash
215+
216+
curl -N -X POST 'https://api.robusta.dev/api/holmes/ACCOUNT_ID/chat' \
217+
--header 'Content-Type: application/json' \
218+
--header 'Authorization: Bearer API-KEY' \
219+
--data '{
220+
"cluster_id": "my-cluster",
221+
"ask": "Which pods are failing in the cluster?",
222+
"stream": true,
223+
"payload": {
224+
"alertname": "KubeContainerWaiting",
225+
"container": "frontend",
226+
"namespace": "production",
227+
"pod": "frontend-59fbcd7965-drx6w"
228+
}
229+
}'
230+
231+
.. note::
232+
The ``-N`` flag disables output buffering in curl, which is important for seeing events as they arrive.
233+
234+
Streaming Response Format
235+
^^^^^^^^^^^^^^^^^^^^^^^^^
236+
237+
The response has ``Content-Type: text/event-stream`` and uses the standard SSE wire format. Each event consists of an ``event`` line specifying the type, a ``data`` line containing a JSON payload, and a blank line:
238+
239+
.. code-block:: text
240+
241+
event: <event_type>
242+
data: <json_payload>
243+
244+
Events are delivered in order as the investigation progresses. A typical stream looks like this:
245+
246+
.. code-block:: text
247+
248+
event: start_tool_calling
249+
data: {"tool_call_id": "call_1", "tool_name": "kubectl_find_resource", "description": "Looking up failing pods"}
250+
251+
event: tool_calling_result
252+
data: {"tool_call_id": "call_1", "name": "kubectl_find_resource", "result": {"status": "success", "data": "..."}}
253+
254+
event: ai_message
255+
data: {"content": "I found a pod stuck in ContainerCreating state. Let me investigate further."}
256+
257+
event: start_tool_calling
258+
data: {"tool_call_id": "call_2", "tool_name": "kubectl_describe_resource", "description": "Describing pod frontend-59fbcd7965-drx6w"}
259+
260+
event: tool_calling_result
261+
data: {"tool_call_id": "call_2", "name": "kubectl_describe_resource", "result": {"status": "success", "data": "..."}}
262+
263+
event: token_count
264+
data: {"input_tokens": 1520, "output_tokens": 305}
265+
266+
event: ai_answer_end
267+
data: {"analysis": "## Investigation Summary\n\nThe pod `frontend-59fbcd7965-drx6w` is stuck ..."}
268+
269+
SSE Event Types
270+
^^^^^^^^^^^^^^^
271+
272+
.. list-table::
273+
:widths: 22 78
274+
:header-rows: 1
275+
276+
* - Event Type
277+
- Description
278+
* - ``start_tool_calling``
279+
- Holmes has started executing a tool (e.g., a ``kubectl`` command). Useful for showing progress indicators.
280+
* - ``tool_calling_result``
281+
- A tool call has completed. Contains the result or error information.
282+
* - ``ai_message``
283+
- An intermediate text message from the AI while it is still investigating. These are partial thoughts, not the final answer.
284+
* - ``ai_answer_end``
285+
- The final analysis. The ``analysis`` field contains the same markdown text you would receive from the non-streaming endpoint. **This is a terminal event** — no more events follow.
286+
* - ``error``
287+
- An error occurred during the investigation. **This is a terminal event.**
288+
* - ``token_count``
289+
- Token usage statistics for the request.
290+
* - ``approval_required``
291+
- Holmes needs user approval before executing a potentially dangerous tool. See :ref:`approval-required-event` below.
292+
293+
Event Payloads
294+
^^^^^^^^^^^^^^
295+
296+
``start_tool_calling``
297+
""""""""""""""""""""""
298+
299+
Emitted when Holmes begins executing a tool.
300+
301+
.. code-block:: json
302+
303+
{
304+
"tool_call_id": "call_abc123",
305+
"tool_name": "kubectl_find_resource",
306+
"description": "kubectl get pods -n production"
307+
}
308+
309+
.. list-table::
310+
:widths: 20 10 70
311+
:header-rows: 1
312+
313+
* - Field
314+
- Type
315+
- Description
316+
* - ``tool_call_id``
317+
- string
318+
- Unique identifier for this tool call. Use it to correlate with the corresponding ``tool_calling_result``.
319+
* - ``tool_name``
320+
- string
321+
- Name of the tool being executed.
322+
* - ``description``
323+
- string
324+
- Human-readable description of what the tool is doing.
325+
326+
``tool_calling_result``
327+
"""""""""""""""""""""""
328+
329+
Emitted when a tool call completes.
330+
331+
.. code-block:: json
332+
333+
{
334+
"tool_call_id": "call_abc123",
335+
"name": "kubectl_find_resource",
336+
"result": {
337+
"status": "success",
338+
"data": "NAME READY STATUS RESTARTS AGE\nfrontend-59fbcd7965-drx6w 0/1 ContainerCreating 0 12m"
339+
}
340+
}
341+
342+
.. list-table::
343+
:widths: 20 10 70
344+
:header-rows: 1
345+
346+
* - Field
347+
- Type
348+
- Description
349+
* - ``tool_call_id``
350+
- string
351+
- Matches the ``tool_call_id`` from the corresponding ``start_tool_calling`` event.
352+
* - ``name``
353+
- string
354+
- Name of the tool that was called.
355+
* - ``result``
356+
- object
357+
- Result object with a ``status`` field (``"success"``, ``"error"``, ``"no_data"``, or ``"approval_required"``) and either a ``data`` field (on success) or an ``error`` field (on failure).
358+
* - ``result_type``
359+
- string
360+
- Optional. ``"txt"`` (default) or ``"png"`` for image results.
361+
362+
``ai_message``
363+
""""""""""""""
364+
365+
Emitted when the AI produces intermediate text during its investigation.
366+
367+
.. code-block:: json
368+
369+
{
370+
"content": "I found a pod stuck in ContainerCreating state. Let me check the events."
371+
}
372+
373+
.. list-table::
374+
:widths: 20 10 70
375+
:header-rows: 1
376+
377+
* - Field
378+
- Type
379+
- Description
380+
* - ``content``
381+
- string
382+
- The text content of the AI's intermediate message.
383+
384+
``ai_answer_end``
385+
"""""""""""""""""
386+
387+
Emitted once when the investigation is complete. This is a **terminal event** — the stream ends after this.
388+
389+
.. code-block:: json
390+
391+
{
392+
"analysis": "## Investigation Summary\n\n**Root Cause**: Missing Secret ..."
393+
}
394+
395+
.. list-table::
396+
:widths: 20 10 70
397+
:header-rows: 1
398+
399+
* - Field
400+
- Type
401+
- Description
402+
* - ``analysis``
403+
- string
404+
- The complete analysis in markdown format. Identical to the ``analysis`` field in the non-streaming response.
405+
406+
``error``
407+
"""""""""
408+
409+
Emitted when an error occurs. This is a **terminal event** — the stream ends after this.
410+
411+
.. code-block:: json
412+
413+
{
414+
"msg": "Failed to connect to cluster",
415+
"error_code": "CLUSTER_ERROR"
416+
}
417+
418+
.. list-table::
419+
:widths: 20 10 70
420+
:header-rows: 1
421+
422+
* - Field
423+
- Type
424+
- Description
425+
* - ``msg``
426+
- string
427+
- Human-readable error message.
428+
* - ``error_code``
429+
- string
430+
- Optional error code identifier.
431+
432+
``token_count``
433+
"""""""""""""""
434+
435+
Emitted with token usage statistics.
436+
437+
.. code-block:: json
438+
439+
{
440+
"input_tokens": 1520,
441+
"output_tokens": 305
442+
}
443+
444+
.. list-table::
445+
:widths: 20 10 70
446+
:header-rows: 1
447+
448+
* - Field
449+
- Type
450+
- Description
451+
* - ``input_tokens``
452+
- integer
453+
- Number of input tokens consumed.
454+
* - ``output_tokens``
455+
- integer
456+
- Number of output tokens generated.
457+
458+
.. _approval-required-event:
459+
460+
``approval_required``
461+
"""""""""""""""""""""
462+
463+
Emitted when Holmes needs explicit user approval before executing a tool. This is a **terminal event** — the stream pauses until approval is granted.
464+
465+
.. code-block:: json
466+
467+
{
468+
"conversation_history": [
469+
{
470+
"role": "assistant",
471+
"content": "I need to run a command that modifies resources.",
472+
"tool_calls": [
473+
{
474+
"id": "call_xyz789",
475+
"pending_approval": true,
476+
"function": {
477+
"name": "kubectl_exec",
478+
"arguments": "{\"command\": \"kubectl delete pod test-pod -n default\"}"
479+
}
480+
}
481+
]
482+
}
483+
]
484+
}
485+
486+
.. list-table::
487+
:widths: 25 10 65
488+
:header-rows: 1
489+
490+
* - Field
491+
- Type
492+
- Description
493+
* - ``conversation_history``
494+
- array
495+
- The full conversation history including the pending tool call. Assistant messages contain a ``tool_calls`` array where entries with ``"pending_approval": true`` are the tools awaiting approval.
496+
497+
Consuming the Stream
498+
^^^^^^^^^^^^^^^^^^^^
499+
500+
**Python (using requests):**
501+
502+
.. code-block:: python
503+
504+
import requests
505+
import json
506+
507+
response = requests.post(
508+
"https://api.robusta.dev/api/holmes/ACCOUNT_ID/chat",
509+
headers={
510+
"Content-Type": "application/json",
511+
"Authorization": "Bearer API-KEY",
512+
},
513+
json={
514+
"ask": "Which pods are failing on cluster prod-us?",
515+
"stream": True,
516+
},
517+
stream=True,
518+
)
519+
520+
event_type = None
521+
for line in response.iter_lines(decode_unicode=True):
522+
if not line:
523+
continue
524+
if line.startswith("event: "):
525+
event_type = line[7:]
526+
elif line.startswith("data: ") and event_type:
527+
data = json.loads(line[6:])
528+
if event_type == "ai_answer_end":
529+
print("Final analysis:", data["analysis"])
530+
elif event_type == "ai_message":
531+
print("AI:", data["content"])
532+
elif event_type == "start_tool_calling":
533+
print(f"Running tool: {data['tool_name']}")
534+
elif event_type == "error":
535+
print(f"Error: {data['msg']}")
536+
event_type = None

0 commit comments

Comments
 (0)