Skip to main content

Duale AI Python SDK

Submit bounded AI agent work to the Duale AI managed runtime and receive typed results in Python. The SDK is not a direct model-provider client.

Status: Public preview. Interfaces can change before a stable release.

Install

The distribution is named dualeai; import it as dualeai. Python 3.10 or newer is required.

python -m pip install dualeai

Before the first request

Before you start, you need a Tenant, an API token, and an eligible model pool. The token identifies the Agent Identity for a Task. Set that identity's public identifier in DUALEAI_AGENT_ID only when you host Tools.

Set DUALEAI_TENANT_ID for Library work. Every Library route takes the Tenant as a path segment, and task-scoped attachments create a Library, so uploads need it too. upload_attachments() does not read DUALEAI_AGENT_ID: it takes an agent_id keyword, and falls back to the sole agent registered on the SDK when exactly one is registered. Pass agent_id=sdk.agent_id to route an upload through the configured identity.

Set the token shown during provisioning:

export DUALEAI_TOKEN=dualeai_your_token_here

Requests use https://api.duale.ai by default. Set DUALEAI_ENDPOINT only when your access instructions name another environment.

Submit a typed Task request

import asyncio

from pydantic import BaseModel

from dualeai import ask, create_sdk


class SupportDecision(BaseModel):
    next_action: str
    reason: str


async def main() -> None:
    async with create_sdk() as sdk:
        response = await ask(
            action="Review this support case and return the next safe action.",
            res=SupportDecision,
            sdk=sdk,
        )
        print(response.task_id)
        decision = await response.model()
        print(decision.next_action)


asyncio.run(main())

Save the example as quickstart.py, then run it:

python quickstart.py

A successful run prints a Task identifier and the validated next action.

ask() returns an AgentResponse handle before the Platform has necessarily accepted the submission. await response.model() waits for the observable outcome and validates a completed Task Result against SupportDecision. Persist response.task_id before waiting so you can reconcile a transport or replay failure.

Before live use

Three boundaries matter before live use:

  • Streaming output can be replaced. Clear accumulated content on BridgeContentResetResponse and take the final result from response.model().
  • Customer Tool handling is not exactly once. For a state-changing Customer Tool, authorize each action and reconcile uncertain External Effects against a durable record.
  • Uncaught Tool exception text can reach a model provider. Do not put credentials, personal data, or other secrets in exception messages.

Next steps

Test without the Platform

MockSDK provides keyed responses and an in-memory Library client for local tests:

import asyncio

from dualeai.testing import MockSDK


async def main() -> None:
    mock = MockSDK()
    mock.set_mock_response("Summarize invoice", {"result": "data"})
    result = await mock.mock_ask("Summarize invoice")
    print(result)


asyncio.run(main())

mock_ask() is a keyed lookup. It does not simulate the real Task transport, streaming, Tool dispatch, or terminal errors.

Contributing and security

See CONTRIBUTING.md for the development workflow. Report suspected vulnerabilities through the private routes in SECURITY.md, not through a public issue.

License

Apache-2.0.

Metadata

Release files for dualeai 0.1.0

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for dualeai 0.1.0
File Size Uploaded
dualeai-0.1.0.tar.gz 128.5 kB Details

Built distribution (wheel)

Table of built distributions (wheels) for dualeai 0.1.0
File Interpreter ABI Platform
dualeai-0.1.0-py3-none-any.whl Python 3 none any Details

Total release size: 280.3 kB

Release files / dualeai-0.1.0.tar.gz

Download URL dualeai-0.1.0.tar.gz
Size 128.5 kB
Tags Source
SHA-256 checksum
How to use checksums
9aac5cf40a58bfa537e5561c1cb3429c803fcdebd0d2d2fb9758b1f470b3a1d3
BLAKE2b-256 checksum
How to use checksums
64eee6fcef02ebc53d14bb795e704d4e1b7ca84aaf8758eaa29218a765e49552
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/7.0.0 CPython/3.13.14

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Sep 21, 2026.

Transparency log

Release files / dualeai-0.1.0-py3-none-any.whl

Download URL dualeai-0.1.0-py3-none-any.whl
Size 151.8 kB
Tags Python 3
SHA-256 checksum
How to use checksums
ea18fe317b2825c7fba4c5e6c2ebc77434dbd8ca3809994883e2bd7282674ed4
BLAKE2b-256 checksum
How to use checksums
a5982da7fba6753c72eb91092347296627ff7c85ce8d5da7954cd4d3af7e2184
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/7.0.0 CPython/3.13.14

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Sep 21, 2026.

Transparency log

Release history Release notifications | RSS feed

This release

0.1.0 This release

2 release files

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page