> ## Documentation Index
> Fetch the complete documentation index at: https://docs.gmicloud.ai/llms.txt
> Use this file to discover all available pages before exploring further.

# Agents and image builds

> Create the Agent that sandboxes launch from, and follow its image build.

An Agent is the reusable definition a sandbox launches from: the container image, data center, size, start command and environment variables. In the Console, this is the Template you register. Creating an Agent builds its image; sandboxes can launch once the build is `ready`.

## Create an Agent

```python Python theme={null}
agent = client.agents.create(
    title="agentbox-demo",
    image_url="docker.io/library/alpine:3.20",
    idc="us-central-iowa16",
    instance_type="gmi.sandbox.small",
    runtime="sandbox",
    env=[{"name": "GMI_MODELS", "value": "llama", "secret": False}],
)
print(agent.slug, agent.launchable)
```

```go Go theme={null}
agent, err := client.Agents.Create(ctx, agentbox.AgentCreateParams{
	Title:        "agentbox-demo",
	ImageURL:     "docker.io/library/alpine:3.20",
	Idc:          "us-central-iowa16",
	InstanceType: "gmi.sandbox.small",
	Runtime:      "sandbox",
	Env:          []map[string]any{{"name": "GMI_MODELS", "value": "llama", "secret": false}},
})
fmt.Println(agent.Slug(), agent.Launchable())
```

| Parameter | Required | Description |
| - | - | - |
| `title` | Yes | Agent name. |
| `runtime` | Yes, for sandboxes | Set to `"sandbox"`. |
| `idc` | Yes, for sandboxes | Data center ID from `client.idcs.list(runtime="sandbox")`. |
| `instance_type` | Yes, for sandboxes | Size ID from `client.products.list(idc_name=..., runtime="sandbox")`. |
| `image_url` | No | Container image. The image needs `bash` if you use the shell. |
| `start_cmd` | No | Command the sandbox runs on start. |
| `env` | No | Environment variables: a list of `{"name", "value", "secret"}`. |
| `ports` | No | Port definitions. |
| `image_credential` | No | Private registry login: `{"username": "...", "secret": "..."}`. |
| `short_desc` | No | Short description. |

A sandbox Agent without `idc` or `instance_type` returns HTTP 422. Creating an Agent does not start a sandbox.

> [!NOTE]
>
> If the Agent's environment includes `GMI_MODELS`, create returns a generated model API key in `generated_api_key`. It is returned only by create, so store it then. Reading or updating the Agent later does not return it.
>
> In Python, read `agent.generated_api_key` right after `create`. `agent.refresh()` and `agent.update()` clear it, and the image-build wait loop calls `refresh()`.

## Wait for the image build

Poll the Agent until `template_build_status` is `ready`. A failed build sets it to `error`, with the reason in `template_build_error`. See the [Quickstart](https://docs.gmicloud.ai/agentbox-sdk/quickstart.md) for a complete wait loop.

A new image can take a few minutes to build. Building the same image again is faster.

## Read build logs

Each build has paged logs. Read them while the build runs to see progress or the cause of a failure.

```python Python theme={null}
import time

from agentbox_sdk import GoneError

builds = agent.list_builds()
build_id = builds[0].id
offset = 0
while True:
    try:
        page = agent.build_logs(build_id, offset=offset)
    except GoneError:
        print("logs no longer available")
        break
    for entry in page.entries:
        print(entry.level, entry.message)
    offset = page.next_offset
    if page.has_more:
        continue
    build = agent.get_build(build_id)
    if build.status in ("ready", "error"):
        final = agent.build_logs(build_id, offset=offset)
        for entry in final.entries:
            print(entry.level, entry.message)
        if build.status == "error" and build.failure is not None:
            raise RuntimeError(build.failure.message)
        break
    time.sleep(2)
```

```go Go theme={null}
builds, err := agent.ListBuilds(ctx)
if err != nil {
	return err
}
buildID := builds[0].ID
offset := 0
for {
	page, err := agent.BuildLogs(ctx, buildID, agentbox.BuildLogParams{Offset: offset})
	if agentbox.IsGoneError(err) {
		fmt.Println("logs no longer available")
		return nil
	}
	if err != nil {
		return err
	}
	for _, entry := range page.Entries {
		fmt.Println(entry.Level, entry.Message)
	}
	offset = page.NextOffset
	if page.HasMore {
		continue
	}
	build, err := agent.GetBuild(ctx, buildID)
	if err != nil {
		return err
	}
	if build.Status == "ready" || build.Status == "error" {
		final, err := agent.BuildLogs(ctx, buildID, agentbox.BuildLogParams{Offset: offset})
		if err != nil {
			return err
		}
		for _, entry := range final.Entries {
			fmt.Println(entry.Level, entry.Message)
		}
		if build.Status == "error" && build.Failure != nil {
			return fmt.Errorf("%s", build.Failure.Message)
		}
		return nil
	}
	time.Sleep(2 * time.Second)
}
```

* Build statuses: `waiting`, `building`, `ready`, `error`.
* `has_more` false only means nothing more is available right now. Keep polling from `next_offset` while the build is `waiting` or `building`, then read one last page after it ends.
* Build logs are not kept long. Once they expire, reading them returns HTTP 410, even for a successful build. Save them yourself during the build if you need them.
* `failure.message` on a failed build is safe to show to end users.

## Get, list, update and delete

```python Python theme={null}
agent = client.agents.get("agentbox-demo")  # by slug
page = client.agents.list(page=1, page_size=20)
agent.update(title="renamed")
agent.delete()
```

```go Go theme={null}
agent, err := client.Agents.Get(ctx, "agentbox-demo") // by slug
page, err := client.Agents.List(ctx, 1, 20)
err = agent.Update(ctx, agentbox.AgentUpdateFields{"title": "renamed"})
err = agent.Delete(ctx)
```

* Updating a locked field returns HTTP 422.
* Deleting an Agent returns HTTP 409 while it still has sandboxes. Delete the sandboxes first, then retry.


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.