Hyperion Actions¶
How your agent talks back to the HyperAI IDE and performs actions.
How it works¶
Every time the user types in the Hyperion panel, the IDE sends your agent a request:
user_idis a UUID generated by the IDE — use it to keep per-user session memorytextis what the user typed.
Your agent answers with a stream of Server-Sent Events. Each event is a
data: line holding one JSON object, followed by a blank line. There are two
kinds of event, and the IDE treats them very differently.
Streaming text¶
Anything you stream as response shows up in the Hyperion panel as the
assistant's message:
Each chunk is an increment, not the whole message — the IDE appends them one after the other, which is what produces the typing effect. The message is complete when your response body closes.
Sending an action¶
When you want the agent to actually do something in the IDE, stream an event
with an action key instead of the response key used for
streaming text:
The IDE executes it and prints nothing for it. If you want to tell the user
what the action did, you have to stream that text yourself as response
events (see Streaming text):
data: {"response": "I'll create the folder "}
data: {"response": "`demo/sub` for you."}
data: {"action": "create_folder", "path": "demo/sub"}
data: {"response": " Done — you can see it in the file explorer."}
Actions and text can come in any order, and you can send several actions in one answer.
Available actions¶
| Action | Payload | What the IDE does | Example |
|---|---|---|---|
create_folder |
path |
Creates the folder. | {"action":"create_folder","path":"demo/sub"} |
delete_folder |
path |
Deletes the folder. | {"action":"delete_folder","path":"demo"} |
create_file |
path, content |
Creates the file and opens it in the editor. | {"action":"create_file","path":"demo/nginx.yaml","content":"apiVersion: hyper.ai/v1\n..."} |
edit_file |
path, content |
Finds the file and replaces it whole, then opens it in the editor. | {"action":"edit_file","path":"nginx.yaml","content":"apiVersion: hyper.ai/v1\n..."} |
delete_file |
path |
Deletes the file. | {"action":"delete_file","path":"nginx.yaml"} |
path is always relative to the workspace root — never absolute, never ...
For delete_file, edit_file and delete_folder you do not need to give the
whole path — send just the name and the IDE searches the workspace and uses the
first match. If you do specify a path, it is taken into account and used
as-is.
Reading a file — the read_file helper¶
Reading a file is deliberately not an action. To see what is inside a file, your agent asks the IDE backend directly over HTTP.
The starter ships that call as a helper in helpers.py:
It returns the file as a plain string.
- The
pathargument is either a full path (demo/sub/app.yaml) or just a file name. Send only the name and the backend searches the whole workspace for it, the same waydelete_filedoes.
Errors
On failure it raises ReadFileError. Possible causes are several files share that
name (all of them listed, so you can ask the user which one), or the backend
is unreachable.
Under the hood read_file is one GET against the IDE backend:
GET http://localhost:3001/api/agent/file?path=app.yaml
GET http://localhost:3001/api/agent/file?path=demo/app.yaml
Slashes are allowed as-is in the query string, so a full path needs no
special treatment (demo%2Fapp.yaml is accepted too).
| Status | Body |
|---|---|
200 |
{"path": "demo/sub/app.yaml", "content": "..."} — path is where it actually lives |
404 |
{"error": "File not found"} |
409 |
{"error": "Ambiguous file name", "matches": [...]} |
Validating a file — the validate_file helper¶
Validating is not an action either. Your agent asks the IDE backend to check a file against the Native Apps or Device Apps rules. You send only the path — the backend reads the file itself.
It returns the report as a dict:
{
"path": "demo/app.yaml",
"type": "device",
"valid": false,
"errors": [
{"line": 3, "column": 1, "endLine": 3, "endColumn": 9, "field": "metadata.name", "message": "is required"}
],
"warnings": [
{"line": 12, "column": 5, "endLine": 12, "endColumn": 12, "field": "spec.exec.retries", "message": "unknown field, not part of the schema"}
]
}
typeisnativeordevice.validisfalseas soon as there is one error.lineandcolumnpoint at the problem. For a missing field they point at the section where it should be added.
The path works the same way as
in read_file — a full path or just a
name.
Errors
On failure it raises ValidateFileError, for the same reasons as
read_file. An invalid file is not an error — you get the report with
valid: false.
Under the hood validate_file is one GET against the IDE backend:
| Status | Body |
|---|---|
200 |
the report |
404 |
{"error": "File not found"} |
409 |
{"error": "Ambiguous file name", "matches": [...]} |
Local vs Docker
If you have followed the challenge description, then when you run the
agent locally the ide-backend is at http://localhost:3001/api. When
the agent runs as a Docker container, the backend must be
http://host.docker.internal:3001/api instead.
In the hyperion-starter
this is already set in the Dockerfile, so nothing to change: