Skip to content

Python SDK

Use the Python SDK when chat operations are part of an application workflow.

Create a client

from skyportalai import Skyportal

client = Skyportal(
    api_key="YOUR_SKYPORTAL_API_KEY",
    base_url="https://app.skyportal.ai",
    timeout=30.0,
    max_retries=2,
)
Parameter Default Description
api_key SKYPORTAL_API_KEY API credential; required
base_url SKYPORTAL_BASE_URL or production API root (trailing slash removed)
timeout 30.0 Per-request timeout seconds; must be greater than zero
max_retries 2 Retry budget for idempotent GET requests; must be zero or greater
session new requests.Session Optional caller-owned session

Prefer a context manager:

from skyportalai import Skyportal

with Skyportal() as client:
    print(client.me().name)

close() only closes sessions created by the SDK. A caller-supplied session remains caller-owned.

Create and monitor a chat

from skyportalai import Skyportal

with Skyportal() as client:
    chat = client.chat.create_chat(
        "Report disk usage and identify the largest directory",
        server_id=42,
    )

    status = chat.wait(timeout=300)
    print(chat.chat_id, status.status)

    for message in chat.messages().messages:
        print(f"{message.role}: {message.content}")

wait() polls while status is processing or uninitialized. It returns on settled state or approval request, and raises WaitTimeoutError on timeout.

Manual approval flow

from skyportalai import Skyportal

with Skyportal() as client:
    chat = client.chat.create_chat("Check disk usage", server_id=42)
    status = chat.wait()

    if status.status == "awaiting_approval":
        for approval in status.pending_approvals:
            print("Requested type:", approval.type)
            print("Requested command:", approval.command)

            # Approve only after authorized human review.
            chat.approve(
                approval.approval_id,
                approval_type=approval.type or "bash_command",
                command=approval.command or None,
            )

        status = chat.wait()

Reject flow:

chat.reject(
    approval.approval_id,
    approval_type=approval.type or "bash_command",
    reason="Outside the approved scope",
)

Optional approval callback:

def approval_policy(approval):
    print(approval.command)
    return None  # Keep pending for separate human decision.

status = chat.wait(on_approval=approval_policy)

Continue, switch, or cancel

chat.send("Now inspect the previous job logs")
chat.select_server(84)
chat.cancel(reason="No longer required")

Read-only observability

execution = chat.execution_status()
events = chat.events(after_timestamp=None, event_types=["tool_call"], limit=100)
tool_calls = chat.tool_calls(limit=100)
reasoning = chat.reasoning(limit=100)
plans = chat.plans()
evaluations = chat.evaluations(evaluator_type=None)
environment = chat.environment()

These methods currently return dictionaries from server payloads. Preserve unknown fields.

Resource-level methods

status = client.chat.get_status(chat_id)
messages = client.chat.get_messages(chat_id, after_sequence=0, limit=100)
client.chat.send_message(chat_id, "Continue")
client.chat.select_server(chat_id, server_id)
client.chat.approve(chat_id, approval_id, approval_type="bash_command", command=command)
client.chat.reject(chat_id, approval_id, approval_type="bash_command", reason=reason)
client.chat.cancel(chat_id, reason="No longer required")

Returned types

Primary models are immutable dataclasses and include raw for forward compatibility.

Type Important fields
User name, raw
Chat chat_id, raw
ChatStatus status, workflow_type, pending_approvals, raw
PendingApproval approval_id, type, command, plan_id, reason, raw
ApprovalResult success, decision, raw
Message role, content, sequence, raw
MessagesPage messages, has_more, raw

Message block payloads are flattened into plain text in Message.content; untouched server values remain in Message.raw.