Skip to content

Manage sessions

Fund, inspect, reuse and finish a session.

On this page

Fund and reuse a session

Use the installed SDK, authenticated wallet and configuration from the quickstart. The Python fragments below run inside its configured Client context. For a complete script that inspects and closes your session, follow the quickstart's final step.

A session holds USDC for one provider and fixed wallet/signer authorities. A caller-selected positive initial_session_tokens value is converted to a conservative deposit using the greatest applicable rate and rounding up. It is working-balance guidance, not a guarantee of a number of output tokens.

Python · explicit pre-warming
opened = client.sessions.open(
    "https://YOUR_PROVIDER",
    model="YOUR_PROVIDER/MODEL",
    initial_session_tokens=10_000,
)
print(opened.operation.state)
if opened.session is not None:
    print(opened.session.session_id.hex())

A usable OpenResult.session requires confirmed funding and a ready authenticated attachment. Retain the operation reference if that outcome is pending or unknown. Reuse the same provider, configuration and session rather than creating replacement funding after an error.

One session can run many requests at once. Share one Client between threads or sub-agents; a second client on the same configuration is refused, and a session has one Control attachment. A run is admitted only when the deposit covers the usage so far and every run in flight at its reserved bound, which for a new run is its prefill plus at least the provider's output buffer. Size initial_session_tokens for all of them together. Each admission may need one voucher round trip. Provider SDKs from 0.2.0 admit waiting runs in the order they first waited; with 0.1.2, a later run can be admitted first.

How usage becomes USDC

Four amounts have different jobs: the deposit funds the session, the signed ceiling authorizes collection, reported usage determines SDK accounting, and confirmed capture records what has actually been paid.

ILLUSTRATIVE · ONE RUN · NO CACHE

1,000 input + 500 output tokens

1 USDC / MTok input · 2 USDC / MTok output

Deposit
1.000000USDC
Funds available in escrow
Signed ceiling
0.010000USDC
Authorized maximum
Reported usage
0.002000USDC
1,000 × 1 + 500 × 2, per million
Confirmed capture
0.002000USDC
Paid only after chain confirmation
After a timely confirmed close: 0.998000 USDC returns from escrow. Network fees are separate.

The example uses illustrative prices of 1 USDC per million input tokens and 2 USDC per million output tokens, with no cached input. It assumes one run, no previous capture and a timely successful close. Network fees are separate; the refund is an escrow amount, not the wallet's net balance after gas.

Exact accounting · amounts in six-decimal USDC base units
run_numerator = (input_tokens - cache_tokens) * input_rate
              + cache_tokens * cache_rate
              + output_tokens * output_rate

session_usage = floor(sum(run_numerator) / 1_000_000)
required_coverage = ceil((usage_numerator + reserved_numerator
                         + candidate_numerator) / 1_000_000)

Use exact integers. Apply the floor once to the accumulated session numerator, across all accepted model/price versions. A per-run receipt amount is informative and non-additive. Cache counts are a subset of input counts and require an accepted cache price; with no cache and zero cache counts, use input and output only.

Unused authorization is not a charge. A capture changes confirmed settlement; it does not add usage or restore consumed reservation. The contract bounds capture by the signed ceiling, deposit and eligibility, but does not verify token counts.

Add funding explicitly

Python · session_id is the retained 32-byte ID
result = client.sessions.topUp(session_id, 1_000_000)
print(result.state, result.operation_ref)

This requests an additional 1 USDC deposit. The amount must be a positive integer in six-decimal base units. It adds no inference usage and changes no accepted run prices. The added funding is usable only after canonical confirmation.

Voucher renewal can happen automatically inside confirmed funding. It never creates an automatic deposit. A failed request does not resume when a later top-up confirms.

To react to low funding, pass on_funding_notice to an explicitly composed Client. It is called only when the confirmed deposit cannot cover what the provider requires, with a FundingNotice whose shortfall is the missing amount in base units, worked out when it is delivered. Requests keep running while a top-up confirms.

Read the final records

Record / What it establishes

Terminal · Complete
The definitive reported run outcome and final counts when validated; successful streaming completion also requires gRPC OK.
Receipt · Control
Final run accounting, checked against the run's accepted terms as its Terminal is. Its chain observation and settled total are the provider's report; the SDK reads no chain for them.
amount
The floored per-run amount; informative, not a separately additive bill.
settled_cumulative
The provider's reported session-wide capture at its stated observation, not necessarily a fresh transaction for this run. The SDK proves the settled total at a cooperative close and checks it at every attachment; sessions.get shows the value its chain follower last read.
Optional settlement reference
A claimed Settled event with a positive delta. The SDK verifies a Terminal's reference on chain; a Receipt's is the provider's report.

Final records do not wait for a new settlement transaction merely to attach a reference. They must agree on session, run, model, prices, counts, status, amount and final meter sequence. Exact repeats do not add usage; conflicts cannot advance validated accounting.

Inspect retained sessions

Python
page = client.sessions.list(limit=100)
for session in page.sessions:
    print(session.session_id.hex(), session.deposit, session.settled_cumulative)
# The built-in client returns at most its one retained session.
view = client.sessions.get(session_id)

list returns at most the built-in client’s one retained session, with next_cursor=None. Pass no cursor; the checked limit is 1–1,000, but this client does not paginate. get reports observed deposit, capture, status, freshness and readiness. Missing local usage is unknown, not zero. Restored inspection and eligible wallet exits can use retained local evidence and the chain without the provider.

Close the quickstart session

After the agent quickstart, return to its folder and terminal with the same provider, wallet and activated environment. Save this as close_session.py to close the retained session and request unused escrow back:

Python · close_session.py
import os
from mppi_agent import Client

with Client.from_config(os.environ["MPPI_PROVIDER"], testnet=True) as client:
    page = client.sessions.list()
    if not page.sessions:
        raise SystemExit("No retained session in this configuration.")
    for session in page.sessions:
        print(session.session_id.hex(), session.status)
    selected = input("Paste the session ID above to close it: ").strip()
    session_id = bytes.fromhex(selected)
    if session_id not in {s.session_id for s in page.sessions}:
        raise SystemExit("That session is not listed in this configuration.")
    result = client.sessions.close(session_id)
    print(result.state, result.operation_ref)
Shell
python close_session.py

The script lists the session retained by this configuration and asks you to paste its ID. A confirmed result establishes the close operation. If it returns pending or unknown, retain the operation reference and run this close script again for the same session; do not repeat inference to resolve payment uncertainty.

Shell · check your wallet after confirmed close
circle wallet balance --address "$MPPI_WALLET" --chain ARC-TESTNET

Unused escrow returns to the funding wallet. Network fees are separate from the inference charge, so the wallet's net balance is not itself an inference receipt. If the provider cannot cooperate, use the session lifecycle guide for wallet-authorized exits.

Close and refund

  1. 01Open

    Funded sessions can admit covered work. Eligible capture keeps the session open.

  2. 02Closing

    A wallet requestClose starts a one-hour collection window. Stop new grants.

  3. 03Closed

    An eligible close or exit transaction completes the transition and returns unused escrow.

  4. 04Cooperative path

    A ready cooperative close can go directly from Open to Closed, without the wallet's waiting period.

Open-session expiry is 24 hours after qualifying confirmed activity. Passing a deadline does not send a refund; an eligible transaction must confirm.

Use sessions.close(session_id) for cooperative close. It stops new grants, accounts for final work, confirms the chain result and refunds unused escrow. Repeat the same close to inspect pending or unknown close intent. A local timeout does not clear that intent.

Exit / Eligibility and effect

requestClose
Funding wallet starts the on-chain Closing interval before open-session idle expiry.
withdraw
Funding wallet exits after the Closing collection deadline; remaining escrow is refunded.
releaseIdle
Permissionless when idle eligibility is met; refund still goes to the funding wallet.

Open-session collection ends 24 hours after qualifying on-chain activity. A timely requestClose starts a full one-hour closing collection window. Positive confirmed top-up and increasing confirmed capture refresh open-session activity; off-chain requests, vouchers and meters do not. Both clocks continue through pauses and outages. At the cutoff, further collection is ineligible; a refund still needs an eligible transaction.

client.close() and stream.close() release local resources. Neither closes escrow. Contract pause and USDC transfer restrictions can also affect exits; inspect confirmed status and operation results.

Reconcile the original operation

Python · retained identifiers
result = client.sessions.reconcile(operation_ref)
print(result.state)
# Authenticated recovery needs the provider and retained evidence.
view = client.sessions.recover(session_id)

Wallet reconciliation uses the original operation reference. Full session recovery needs authenticated Control and complete retained evidence; it does not generate a new deposit or replay inference. Cooperative close is reconciled by repeating the same close request.

If a confirmed close exceeds validated usage, CloseAccountingError retains the confirmed operation. Treat it as an accounting discrepancy, not a failed transaction to submit again. Preserve evidence and investigate with the provider.

Manage sessions | Agents | MPPI Docs