• Compute
  • Customers
  • Pricing
Sign In
More Blog Posts
XDiscordLinkedInYouTube

Products

  • GPUs
  • Inference
  • Studio

Developers

  • Model library
  • Documentation
  • Glossary

Company

  • About Us
  • Blog
  • Events
  • Partnership
  • Scale
  • Career
  • Ambassador program
  • Mission & Vision

Popular models

    Stay in the loop

    By submitting, you acknowledge that we may collect and use the information you provide, which may include personal information.

    XDiscordLinkedInYouTube

    Copyright ©2026 All rights reserved.

    Privacy PolicyTerms of UseLegal Documentation
    More Blog Posts
    Other

    Hosting Platforms for Long-Running Research Agents That Keep State and Call Models on the Same Network

    September 25, 2026

    GMI Agentbox hosts long-running research agents with runtime and model access on one GMI Cloud account and network. It is in early access and combines runtime and model billing on one invoice.

    A multi-day run needs three independent safeguards:

    Elapsed timeWhat the run is doingWhat the platform has to get right
    Hour 1Planning, first search passes, first few hundred model callsA runtime lifetime longer than the default, and a renewal path that does not race the expiry
    Hour 24Partial findings accumulated, several tool chains deepState that survives a container restart, because nothing useful lives in memory anymore
    Hour 72Synthesis, long-context passes over everything gatheredModel calls that have not drifted onto a second vendor, a second key, and a second bill

    GMI Cloud combines GPU infrastructure, model serving, and agent runtimes on one platform.

    What actually breaks when an agent runs for 72 hours instead of 20 minutes?

    A 72-hour run can fail through lease expiry, loss of in-memory state after restart, or model calls crossing a vendor boundary. Address each separately.

    1. Lifetime. Sandboxes expire on a timer. On GMI Cloud's Sandbox API, when timeout is "omitted or 0 or less, 300 seconds is used" (Create a sandbox). A three-day run is 864 default windows long. Something has to push that expiry forward, reliably, for 72 hours.
    2. State. GMI Cloud's own guidance is blunt: "GMI containers are stateless. If a container restarts, any in-memory job state is lost." (Handle long-running requests) A 20-minute agent can get away with in-process state. A 72-hour agent cannot.
    3. The model call path. A long run makes thousands of model calls. If the runtime is on one vendor and the models are on another, every call pays the cost of crossing between them. GMI Cloud's framing of why Agentbox colocates the two: "Because compute and inference run on the same network, agents in production don't pay the latency, egress, or operational cost of stitching together vendors." (Agentbox FAQ)

    Agentbox lists ephemeral, long-running, and always-on tiers. Long-running covers persistent state across multi-step jobs, including deep research, document pipelines, and routing; always-on retains memory and identity across sessions. The product page advertises sessions 30× longer than a 24-hour sandbox. (GMI Agentbox)

    How do you keep a runtime alive for days without leaving it alive forever?

    Renew the lease while work continues; a create-time timeout alone does not sustain a multi-day run.

    POST /sandboxes/{id}/timeout sets TTL in seconds from the current time. Its four relevant properties are: (Set sandbox timeout)

    • It resets, it does not accumulate. Each successful call measures the new TTL from the moment of the call, so renewing early costs you nothing and gains you nothing beyond the fresh window.
    • The response is authoritative. The body returns old_end_at and new_end_at. Schedule the next renewal against new_end_at, not against your own clock arithmetic.
    • It only works while the sandbox is running. Any other state returns 409. That status is the signal to stop the run and resume from a checkpoint, not to retry.
    • Extending the lease invalidates your cached credentials. This is the detail that quietly breaks keepalive loops written the obvious way. The docs are explicit: "After extending a sandbox's lifetime (via connect or the timeout endpoint), call connect again and overwrite all three cached values", because the token may have been re-signed (Sandbox API overview). The connect reference repeats it per field: "Re-read this field and sandbox_access_token on every connect; do not reuse values cached from a previous create/connect."

    Prefer POST /sandboxes/{id}/connect for keepalive: its timeout is extend-only, and an extension returns the re-signed token, end_at, sandbox_key, and domain. Use /timeout for an independent reset or a shorter TTL, then reconnect to refresh credentials. (Connect to a sandbox)

    Picking a TTL and a renewal interval

    Choose a TTL and renewal interval together. Their ratio controls retry headroom; the TTL caps how long an abandoned runtime remains billable.

    For a 72-hour run (259,200 seconds):

    TTL per renewalRenewal intervalRenewal attempts inside each TTL windowRenewal calls across the runWorst-case orphan window if the orchestrator dies
    300 s (the default)60 s44,3205 minutes
    1,800 s300 s586430 minutes
    3,600 s600 s54321 hour
    21,600 s1,800 s111446 hours

    Keep TTL at least four times the renewal interval, capped by the acceptable orphan cost. A 3,600-second TTL renewed every 600 seconds needs 432 calls over 72 hours, leaves five further attempts per window, and limits an orchestrator crash to at most one extra billable hour.

    The renewal loop

    The loop handles renewal, credential rotation, failures, and teardown:

    import os
    import random
    import re
    import threading
    from datetime import datetime, timezone

    import requests

    CONTROL_PLANE = "https://console.gmicloud.ai/api/v2"
    HEADERS = {"Authorization": f"Bearer {os.environ['GMI_SANDBOX_API_KEY']}"}

    TTL_SECONDS = 3600 # lifetime each renewal grants
    RENEW_EVERY = 600 # five more attempts fit inside every TTL window
    SAFETY_MARGIN = 30 # stop trusting the lease this long before it expires
    HTTP_TIMEOUT = 10
    RETRYABLE = {429, 500, 502, 503, 504}
    _FRACTION = re.compile(r"(?<=:\d\d)\.(\d+)") # RFC 3339 allows any number of digits


    class SandboxGone(RuntimeError):
    """The runtime is no longer usable, so the run must resume from a checkpoint."""


    def _expiry(value):
    """Parse an RFC 3339 expiry, tolerating nanoseconds and rejecting naive values."""
    if not isinstance(value, str):
    raise ValueError(f"expected a timestamp string, got {type(value).__name__}")
    normalized = _FRACTION.sub(lambda m: "." + m.group(1)[:6].ljust(6, "0"), value)
    parsed = datetime.fromisoformat(normalized.replace("Z", "+00:00"))
    if parsed.tzinfo is None:
    raise ValueError(f"timestamp carries no UTC offset: {value}")
    return parsed


    def connect(sandbox_id, ttl=TTL_SECONDS, http_timeout=HTTP_TIMEOUT):
    """Extend the lease and return the credentials the extension just re-signed."""
    response = requests.post(
    f"{CONTROL_PLANE}/sandboxes/{sandbox_id}/connect",
    headers=HEADERS, json={"timeout": ttl}, timeout=http_timeout,
    )
    if response.status_code in (404, 409):
    raise SandboxGone(f"connect returned {response.status_code}")
    response.raise_for_status()
    payload = response.json()
    data = payload.get("data") if isinstance(payload, dict) else None
    if not isinstance(data, dict):
    raise ValueError("connect response carried no data object")
    return data, _expiry(data["end_at"])


    class Lease:
    """Thread-safe holder for the credentials and expiry that renewal keeps replacing."""

    def __init__(self, data, deadline):
    self._lock = threading.Lock()
    self.stop = threading.Event()
    self.failure = None
    self.refresh(data, deadline)

    def refresh(self, data, deadline):
    # build the whole snapshot first: a missing field must not half-apply
    snapshot = (f"https://{data['sandbox_key']}.{data['domain']}",
    data["sandbox_access_token"], deadline)
    with self._lock:
    self._base_url, self._token, self._deadline = snapshot

    def credentials(self):
    with self._lock:
    return self._base_url, self._token

    def headroom(self):
    with self._lock:
    deadline = self._deadline
    return (deadline - datetime.now(timezone.utc)).total_seconds() - SAFETY_MARGIN

    def give_up(self, reason):
    self.failure = reason
    self.stop.set()


    def keepalive(sandbox_id, lease):
    """Thread entry point. However this ends, the lease is left signalled."""
    try:
    _renew_until_stopped(sandbox_id, lease)
    except BaseException as exc: # nothing raised in a worker reaches the caller
    lease.give_up(exc)
    raise
    finally:
    lease.stop.set() # the main loop must never wait on a dead worker


    def _renew_until_stopped(sandbox_id, lease):
    backoff = 1.0
    while not lease.stop.is_set():
    headroom = lease.headroom()
    if headroom <= 0:
    return lease.give_up("ran out of renewal headroom")
    try:
    # bound the request so a hung call cannot outlive the lease it renews
    data, deadline = connect(sandbox_id, http_timeout=min(HTTP_TIMEOUT, headroom))
    lease.refresh(data, deadline)
    backoff, wait_for = 1.0, RENEW_EVERY
    except SandboxGone as exc:
    return lease.give_up(exc)
    except (requests.RequestException, KeyError, TypeError, ValueError) as exc:
    status = getattr(getattr(exc, "response", None), "status_code", None)
    if status is not None and status not in RETRYABLE:
    return lease.give_up(exc)
    wait_for = backoff
    backoff = min(backoff * 2, 60.0)
    remaining = lease.headroom()
    if remaining <= 0:
    return lease.give_up("ran out of renewal headroom")
    lease.stop.wait(min(wait_for, remaining) * random.uniform(0.85, 1.0))


    def teardown(sandbox_id):
    """Best effort. Delete acceptance is the billing cutoff, so never skip it."""
    try:
    response = requests.delete(
    f"{CONTROL_PLANE}/sandboxes/{sandbox_id}",
    headers=HEADERS, timeout=HTTP_TIMEOUT,
    )
    if response.status_code not in (202, 404):
    print(f"delete not accepted ({response.status_code}); sweep this id later")
    except requests.RequestException as exc:
    print(f"delete call failed ({exc}); sweep this id later")


    def run_research_agent(sandbox_id, steps, execute, checkpoint):
    lease = None
    try:
    lease = Lease(*connect(sandbox_id))
    threading.Thread(target=keepalive, args=(sandbox_id, lease), daemon=True).start()
    for step in steps:
    if lease.stop.is_set():
    raise SandboxGone(f"lease lost, resume from the checkpoint: {lease.failure}")
    base_url, token = lease.credentials() # re-read, renewal replaces both
    checkpoint(step, execute(base_url, token, step))
    if lease.stop.is_set(): # also check after the last step
    raise SandboxGone(f"lease lost during the final step: {lease.failure}")
    finally:
    if lease is not None:
    lease.stop.set()
    teardown(sandbox_id) # runs even if connect never succeeded

    The loop renews through connect and updates all three credentials atomically. A shared stop flag carries worker-thread failure to the main loop, which checks it before each step and after the last. Requests are bounded by remaining lease time; jitter prevents synchronized renewals. Teardown runs even if initialization fails. DELETE returns 202 and is replayable while deletion is already underway. (Delete a sandbox)

    Tag each sandbox with the run ID. GET /sandboxes supports AND-ed metadata filters so fleet cleanup can find orphaned instances. (List active sandboxes)

    Where should a multi-day research agent keep its state?

    A multi-day research agent keeps its state outside the container, in a store you control, written at every step boundary.

    Use an async job pattern: return job_id with HTTP 202, run work in the background, and poll status every 3–5 seconds. Persist state to Redis or a database, not memory, and inject store credentials as Secrets during agent registration. (Handle long-running requests)

    Three platform facts shape how you lay that out:

    • Resources are fixed at creation. vcpu, memory_mb, and disk_mb are immutable after a sandbox is created (Get sandbox details). You cannot grow a long-running agent's memory mid-run, so size the template for the worst step in the plan, not the average one.
    • Lifecycle states are observable. GET /sandboxes/{id} reports provisioning, running, checkpointing, updating, or failed, plus the authoritative end_at and a failure object that is "Non-empty only when state=failed." A supervisor that polls this is how you distinguish "the agent is thinking" from "the runtime is gone".
    • The data plane is separate. Lifecycle calls go to the control plane at https://console.gmicloud.ai/api/v2 with a bearer API key; commands and files go to https://{sandbox_key}.{domain} with an X-Access-Token header, and the two credential types are not interchangeable (Sandbox API overview). The Python SDK (pip install gmi-sandbox-sdk) wraps both, including sandbox.files.upload() and sandbox.files.download() for moving checkpoints in and out (SDK usage).

    The checkpoint decision, and what it saves

    For long idle gaps, compare keeping the runtime alive with checkpointing, deleting, and resuming it.

    Hosted Agentbox containers are billed for their full running lifetime, including idle time, until DELETE /v1/containers/{id}. Auto-pause is under exploration. For Sandbox v2, accepted deletion time is the usage-accounting cutoff. (Agentbox FAQ; Isolation is the easy half of the sandbox problem)

    Consider a 72-hour run with 11 active hours and 61 waiting on sources, embargoes, or review:

    DesignBillable runtime hoursRelative cost
    One runtime held open for the whole run721.00×
    Checkpoint to external state, delete between phases, resume on a fresh runtime110.15×

    Delete and resume when an idle gap exceeds checkpoint-write plus recreation-and-reload time. GMI's public-network cold-create test reports 0.21 seconds median and 0.26 seconds p95 to Running, but restoring your state adds time. Measure your complete recovery cycle rather than applying the create benchmark alone. (Isolation is the easy half of the sandbox problem)

    What does "same network" actually mean here, and how do you get it?

    GMI's Verified configuration pairs Cluster Engine compute with GMI Models inference. The same-network claim applies to that deployment configuration:

    • Agentbox is "backed by GMI's model access, same-network inference, and managed compute", and runs its workload tiers "with same-network inference behind every call".
    • On cost, "Calls stay on GMI's own network. Model access and inference, one invoice."
    • On the Verified badge: an agent earns it when it runs entirely on GMI infrastructure, "GMI Cluster Engine for compute and GMI Models for inference, all on GMI's NVIDIA GPU fleet. Both layers share the same network, so execution and model calls don't leave GMI."

    Build toward the Verified configuration and record the serving route during onboarding when same-network execution is mandatory.

    GMI MaaS describes models hosted on GMI's data center infrastructure. Long-context open-weight models can support later synthesis passes over accumulated research. The following are October 2026 list prices:

    Model IDContextInput per 1M tokensOutput per 1M tokens
    deepseek-ai/DeepSeek-V4-Flash-0731~1M tokens$0.44$1.32
    Qwen/Qwen3-Coder-480B-A35B-Instruct-FP8~262K tokens$0.90$4.50
    zai-org/GLM-5.1-FP8202,752 tokens$1.40$4.40

    Check the model library before budgeting. DeepSeek-V4-Flash-0731 had a 35% discount on October 15, 2026, at $0.286/$0.858; the table uses undiscounted rates. Confirm and record each model's serving route when network residency is a requirement. (console.gmicloud.ai/model-library)

    At 1,200 calls averaging 20K input and 2K output tokens, a run uses 24M input and 2.4M output tokens. At list rates, DeepSeek-V4-Flash-0731 costs $10.56 + $3.17 = $13.73, Qwen3-Coder-480B-A35B-Instruct-FP8 costs $32.40, and GLM-5.1-FP8 costs $44.16. Ten times the traffic multiplies each figure by ten; model choice changes inference spend by over 3x without changing runtime hours.

    The catalog also provides proprietary frontier models through one account, OpenAI-compatible API, and invoice. For weights that must run on reserved single-tenant GPUs, use GMI Cloud Prime Inference under the same account and agree on the serving configuration explicitly.

    Which hosting platform should you pick?

    Evaluate Agentbox for runtime and MaaS for models against these seven requirements:

    #RequirementWhere it lands on GMI Cloud
    1A documented way to extend a running session, with the new expiry returnedPOST /sandboxes/{id}/connect and POST /sandboxes/{id}/timeout, returning end_at and old_end_at / new_end_at
    2A documented credential-refresh rule after an extensionCall connect again and overwrite all three cached values
    3An explicit statement of what happens to in-container state"GMI containers are stateless", with the async job pattern and external store prescribed in docs
    4Observable lifecycle states and an authoritative expiry fieldGET /sandboxes/{id} returning state and end_at
    5Model access on the same network as the runtime"Calls stay on GMI's own network.", with the Verified criterion defining what qualifies
    6One invoice across runtime and inference, and one key across models"1 invoice" covering "Runtime + models + billing"; "200+ Models available in one key"
    7A stated billing cutoff you controlBilled until DELETE is called, with delete acceptance as the accounting cutoff

    Agentbox provides per-user isolated runtimes; MaaS supplies 200+ models. For dedicated capacity, October 2026 starting GPU rates are H100 $2.60/hour and H200 $3.20/hour. Agent registration currently lists a 2 vCPU, 4 GB RAM container with 10 GiB ephemeral and 30 GiB data storage in IOWA IDC-1 (US-IA, US); more tiers and regions are planned. Agentbox remains in early access. Confirm that the largest step fits the available tier, region, and onboarding path. (GMI Agentbox; GMI MaaS; GMI Cloud GPU infrastructure; Register an agent)

    Companion articles cover hosted-agent runtime logs, usage, and cost dashboards, and Grok 4.6 for long-running workflows. (runtime logs, usage, and cost dashboards for hosted agents; Grok 4.6: A New Option for Long-Running Agent Workflows)

    FAQ

    Can a sandbox on GMI Cloud stay alive for days? Yes, if the lease is renewed while the sandbox remains running. The default timeout is 300 seconds. Both connect and timeout can extend lifetime; connect also returns refreshed credentials. The Agentbox page positions the service for seconds-to-days workloads and advertises sessions 30× longer than a 24-hour sandbox.

    What happens to my agent's state if the container restarts? In-memory state is lost. Persist job state externally, inject store credentials as Secrets, and checkpoint at every step boundary.

    Do I have to re-fetch credentials after extending a session? Yes. A lifetime extension may re-sign the access token. Reconnect and replace sandbox_key, domain, and sandbox_access_token together; renewing through connect performs both operations in one call.

    What does same-network inference mean on Agentbox? The documented Verified setup uses GMI Cluster Engine for compute and GMI Models for inference on GMI's GPU fleet, keeping execution and model calls within GMI's network. Confirm that configuration for your deployment.

    Am I billed while a long-running agent sits idle? Yes. Hosted containers remain billable while idle until deletion; auto-pause is not a current assumption. Checkpoint and resume across long gaps when recovery costs less than holding the runtime.

    Do I need a second vendor for model access? No. Runtime and access to 200+ models share one account and invoice, with separate usage line items. Add Prime Inference when reserved single-tenant model serving is needed.

    Is GMI Agentbox generally available? No. It is labeled early access, although published workloads include Oqoqo's evaluation runs at up to 50,000 concurrent sandboxes. Confirm tiers, regions, and onboarding for your workload. (GMI Agentbox)

    Next step

    Test one 72-hour private run and record renewals, checkpoints, tokens, and billable hours. Start in the Console with one sandbox and a 3,600-second lease, or ask the GMI Cloud team to size the runtime tier, region, and model mix. (talk to the GMI Cloud team)

    Colin Mo

    Build AI Without Limits

    GMI Cloud helps you architect, deploy, optimize, and scale your AI strategies

    FAQ

    Yes, if the lease is renewed while the sandbox remains running. The default timeout is 300 seconds. Both connect and timeout can extend lifetime; connect also returns refreshed credentials. The Agentbox page positions the service for seconds-to-days workloads and advertises sessions 30× longer than a 24-hour sandbox.

    Ready to build?

    Explore powerful AI models and launch your project in just a few clicks.

    Get Started