Install the Python SDK
wexa is a single-module HTTP client for the Wexa gateway. No dependencies at all — it is built
on urllib from the standard library — and it supports Python 3.9 and later.
Install
pip install wexa
The current published version on PyPI is 0.1.2. Confirm what you actually got:
import wexa
print(wexa.__version__) # 0.1.2
Reaching a tool with no method on 0.1.2
An unrecognised tool name is sent to the wire verbatim rather than rejected, and the name-to-path
transformation is the same mechanical one. So every tool the gateway registers is reachable from
0.1.2 through call():
fabric.call("delete-context", label="Customer", key="id", value="c-1")
With 0.1.2 installed from PyPI, that reached
POST /v1/delete-context — the gateway's own access log recorded
POST /v1/delete-context -> 404, so the 404 was the gateway saying the tool is not registered in
that deployment, not the client failing to route it.
Configure
export WEXA_WORKSPACE=https://fabric.wexa.ai # your workspace URL
export WEXA_API_KEY=fab_sk_… # any bearer credential the gateway accepts
WEXA_WORKSPACE is the workspace URL, not the API base. The client discovers the API base from
GET /v1/connection-info itself. Trailing slashes are stripped for you.
Construct the client
from wexa import Fabric
fabric = Fabric() # reads the two environment variables
# or
fabric = Fabric(workspace="https://fabric.wexa.ai", api_key=my_key)
Constructor options
| Option | Default | What it does |
|---|---|---|
workspace | WEXA_WORKSPACE | Workspace URL. |
api_key | WEXA_API_KEY | Bearer credential. |
timeout | 70 | Seconds. Governed tool routes cap near 60s upstream, so 70 lets the server's own deadline fire first. |
retries | 3 | Attempts when a call passes retry=True. Total, not extra. |
Discovery happens in the constructor
Unlike the TypeScript client, the Python client performs the /v1/connection-info round trip inside
__init__, so fabric.base is populated the moment the object exists:
fabric = Fabric()
print(fabric.base) # http://localhost:7123/v1
print(fabric.issuer) # http://localhost:7123
That means constructing a client is a network operation. Construct it once and reuse it; do not build one per request.
Verify the install
from wexa import Fabric
fabric = Fabric()
print(fabric.whoami())
With 0.1.2 installed from PyPI:
{'dept_id': 'dept_c10', 'org_id': 'org_c10', 'project_id': 'proj_c10',
'role': 'OWNER', 'user_id': 'u_c10',
'grants': ['fabric:query.read', 'fabric:docs.read', 'fabric:ontology.write',
'fabric:orchestrate.read', 'fabric:orchestrate.write', 'fabric:agent.run',
'fabric:skill.write', 'fabric:model.write']}
There is nothing to release. urlopen closes per request, so the client has no close() and needs
none.
One SDK ported to the other
wexa and @wexa-fabric/sdk are deliberate ports of one another, not two independent libraries and
not a stack. Neither wraps the other; both are thin HTTP clients for the same gateway. Python is the
source of truth and TypeScript is the port, and they share one tool table, one set of server-bound
arguments, one error taxonomy, one retry policy and one response envelope.
They are not byte-identical, and a handler moved between them needs four adjustments:
| Python | TypeScript | |
|---|---|---|
| Nothing reached the gateway | urllib's URLError, an OSError — not a WexaError | TransportError, which is a WexaError |
| The 504 class | TimeoutError_, underscored to dodge the builtin | TimeoutError |
| Retry predicates | isinstance(e, RETRYABLE) / RESUME_RETRYABLE | isRetryable(e) / isResumeRetryable(e) |
| Discovery | In __init__ | Deferred to the first call |
Catch WexaError and OSError in Python. A lone except WexaError will not see a refused
connection, and that is the failure most likely to happen in production.