Python API reference
Use these tables to find SDK classes and methods by task. They summarize common public interfaces; the numbered chapters explain how to use them. They are not an exhaustive generated inventory, so consult your installed package's signature for newer options. async marks coroutine methods, and / joins retained aliases. Names normally come from atfgraph; rows name a submodule when needed.
Authoring
| Name | Purpose |
|---|---|
Agent(node_id, *, graph_server=None, version="0.1.0", api_key=None, description="", capacity=8, max_waiting=None, model=None, client=None, poll_interval=0.1, tags=None, sync_emitters=True, harness_provider=None, harness_cwd=None, media=None, http_pool=None, record_usage_events=True, report_usage=True) | One label + version worth of capabilities, plus the client and worker that serve them |
AgentRouter(prefix="", tags=None) | A group of handlers an Agent includes; decorated functions stay callable |
CapabilityEntry | The registered handler record returned by Agent.add / Agent.entry |
traversal(name=None, *, agent=None, **options), skill(...) | Module-level decorators on the current agent (Agent.set_current) |
traverse(target, *args, **kwargs) | Module-level nested call using the current execution context's agent |
capability_to_tool_schema(target, capability) | OpenAI-format function tool for one label.capability |
Choose an Agent method according to the work you need to do:
| Theme | Methods |
|---|---|
| Registration | traversal(name=None, **options), skill(name=None, **options), add(kind, func, name=None, **options), include_router(router), capabilities(), definition(), entry(capability), target(capability), label, set_current(), async register() |
| Serving | run(*, capacity=None, once=False, register=True), async serve(*, stop=None, capacity=None, register=True, once=False, sync_emitters=None, startup_timeout=30.0), attach_worker(worker), worker, bind_client(client), use_transport(transport), client |
| Calling | async traverse(target, *args, timeout=None, **kwargs) / call, traverse_sync(...), async submit(target, input=None, *, session_id=None, operation_key=None, idempotency_key=None, version=None), async call_local(capability, *args, **kwargs) |
| Context | ctx, cancel_requested(), async progress(data), async note(message, tags=None), async bind_session(session_id), async request_approval(prompt, *, operation_key, checkpoint=None) / pause, async save_checkpoint(name, value, *, expected_revision=None), async load_checkpoint(name, default=None) |
| Facades | memory, knowledge, emitters, discovery, identities, credentials, observability, media, model, http_pool |
| Model and media | async ai(...), ai_with_vision, ai_with_audio, ai_with_multimodal, ai_generate_image, ai_generate_audio, ai_generate_music, ai_generate_video, ai_transcribe_audio, async realtime_session(*, model=None, provider="openai", transport="websocket", **options) |
| Harness | async harness(prompt, *, provider=None, schema=None, cwd=None, **options), harness_doctor(providers=None) |
| Emitters | emitter_bindings(), has_emitter_bindings(), async sync_emitters(), synced_emitters, webhook_urls(), on_change(patterns, **options) |
| Discovery | async discover(**filters) |
| Usage and logs | cost_tracker(), execution_cost(), async record_usage(entry), usage_reporting(), enable_node_logs(logger=None, *, level=20, max_pending=1000, batch_size=100, flush_interval=1.0, exclude=()), async disable_node_logs(), node_logs |
AgentRouter groups handlers before an Agent includes them. It provides traversal(...), skill(...), add(kind, func, name=None, *, max_attempts=1, timeout_seconds=300, description=None, input_schema=None, output_schema=None, tags=None, triggers=None, accepts_manual_emitters=True), async ai(...), async traverse(...), async submit(...), and memory.
The client and server facades below use HTTP. Local helpers such as trackers, rate limiters and caches keep state in the worker process unless their documentation explicitly describes server storage.
Client
| Name | Purpose and methods |
|---|---|
Client(server=None, *, api_key=None, bearer_token=None, edge_auth=None, timeout=30.0, poll_interval=0.2, max_poll_interval=2.0, transport=None, headers=None, limits=None, stream_limits=None, http2=False, max_in_flight=100, max_pending=1000) | Async client; one per event loop, use async with. Traversers: async submit(target, input=None, *, version=None, session_id=None, idempotency_key=None, parent_step_id=None, operation_key=None, parent_lease_token=None), traverse(target, input=None, *, timeout=None, **submit_kwargs), wait(traverser_id, *, timeout=None, poll_interval=None), get, cancel, path, event_log(traverser_id, after=0), events(traverser_id, *, last_event_id=None, reconnect=True, max_reconnects=20), list_traversers. Registry: register_agent(label, version, capabilities), capabilities(label, version=None), list_agents. Sessions: create_session. Memory: memory_read, memory_write, memory_delete. Approvals and checkpoints: request_approval(*, operation_key, prompt, checkpoint=None, pause=True), get_approval, list_approvals, decide_approval(approval_id, decision, response=None), put_checkpoint, get_checkpoint. Artifacts: put_artifact, get_artifact, read_artifact, list_artifacts, delete_artifact. Server: health, server_info. Worker protocol: worker_enroll, worker_claim, worker_renew, worker_progress, worker_suspend, worker_resume, worker_complete, worker_drain. Also server, transport, async aclose |
Handle | A submitted traverser (id, step_id, status, target): async result(timeout=None), wait(timeout=None, *, poll_interval=None), refresh, cancel, path, event_log(after=0), events(last_event_id=None), last |
ATFGraphClient | Compatibility adapter: execute returns {"result": ..., "status": ...}; execute_async, wait_for_execution_result, poll_execution_status, cancel_async_execution, create_session, aclose |
Submission, TraverserResult, Path, PathStep, Event, AgentDefinition, Capability, ServerInfo, ClaimedTask, MemoryValue | Wire models. TraverserResult has status, output, error, is_terminal, ok; Path.items holds PathSteps with step_id, traverser_id, target, status, parent_step_id, attempts, raw; Event has sequence, type, data |
TERMINAL_STATES | frozenset({"succeeded", "failed", "cancelled", "timed_out"}) |
UsageEvent | A usage entry recorded as a progress event; UsageEvent.from_event(event) returns None for other events |
Execution context
| Name | Purpose and methods |
|---|---|
ExecutionContext | The leased task: fields traverser_id, step_id, root_id, target, version, lease_token, attempt, session_id, worker_id, trigger, input, parent_id; properties label, capability, traversal_name, agent_node_id, is_root, execution_id, parent_execution_id, run_id, workflow_id, effective_session_id, emitter, via_emitter, cancel_requested, child_waits, permit_released; operation_key(target, payload), child(**overrides) |
current_context(), require_context() | The current context, or None / NoExecutionContext |
use_context(ctx) | Context manager binding an explicit context (tests, scripts) |
session_scope(session_id) | Within a handler, direct default memory and child submissions at session_id |
Memory and knowledge
| Name | Purpose and methods |
|---|---|
Memory | app.memory: scope factories session(session_id=None), actor(actor_id=None), workflow(root_id=None), global_() / global_scope(), default(); direct operations with scope=: async get, read, set, update, delete, exists, keys, list_keys, set_vector, get_vector, delete_vector, similarity_search, search, changes; watch(patterns=None, *, scope=None), on_change(patterns, *, scope=None, after=0, interval=0.25), async run_subscriptions(stop) |
MemoryScope | One bound scope with the same operations: read, get, exists, set, delete, update, keys, list_keys, set_vector, get_vector, delete_vector, similarity_search, search, changes, watch, subscription |
MemoryChangeEvent, ChangePage, KeyPage, VectorValue, VectorMatch, SearchResult | Change-feed entries (action is set or delete), key pages and vector results |
Knowledge(client_provider, scope="global", *, session_id=None, actor_id=None, root_id=None, normalize=True) | Scope-bound document knowledge (BM25): async put(doc_id, text=None, *, title=None, chunks=None, metadata=None, chunk_size=None, chunk_overlap=None, expected_revision=None), put_many(documents), get(doc_id, *, include_chunks=True), list(*, prefix=None, cursor=None, limit=None), documents(...), delete(doc_id, *, expected_revision=None), search(query, *, top_k=10, offset=0, filters=None, doc_id=None, min_score=None), search_all(...), static search_across(scopes, query, ...), stats(); scope(scope, ...), semantic(embedding, *, index="knowledge", filter_keys=None), label |
KnowledgeHit, KnowledgeSearchResult, KnowledgeDocument, KnowledgeChunk, KnowledgeDocumentSummary, KnowledgeListing, KnowledgeWriteResult, KnowledgeBatchResult, KnowledgeStats | Results. KnowledgeSearchResult.citations() and context(max_chars=...); KnowledgeHit.citation is doc_id#ordinal |
chunk_text(...) | Preview of the server's chunker (same algorithm) |
SemanticKnowledge | Semantic and hybrid retrieval over one scope: async put, put_many, delete, search, stats, embed_query, reindex, reindex_all; scope, config, dimension |
EmbeddingConfig(provider, model, dimension=..., batch_size=..., concurrency=..., max_attempts=..., retry_delay=...), EmbeddingProvider, Embedder, http_embedding_provider(url, model, api_key=None) | How chunks and queries are embedded; EmbeddingProvider is the callable type Sequence[str] -> Sequence[Sequence[float]] |
SemanticHit, SemanticSearchResult, SemanticWriteResult, SemanticBatchResult, SemanticStats, IndexResult, IndexFailure | Semantic results and indexing outcomes |
Model and media
| Name | Purpose and methods |
|---|---|
ModelProvider | Base: async complete(...), stream(...); provider_name, capabilities |
HTTPChatModel, AnthropicMessagesModel | OpenAI-compatible /chat/completions and Anthropic Messages providers; from_env(), complete, stream |
ModelResponse | text, parsed, model, usage, tool_calls, finish_reason, provider, audio, images; wants_tools, cost_usd, assistant_message() |
ModelStream, StreamEvent | Async iterator from ai(stream=True): text(), collect(), response(), aclose() |
ToolCall, ToolCallResponse, ToolCallRecord, ToolCallTrace | Result of app.ai(tools=...): final text or parsed output plus the full trace |
HTTPPool | One bounded httpx.AsyncClient shared by every provider: client(), request, stream, aclose |
Image, Audio, Video, File, Text | Input parts; Image.from_url/from_file/from_bytes, Audio.from_url/from_file/from_bytes, to_part(). Helpers image_from_url, image_from_file, audio_from_url, audio_from_file, video_from_url, video_from_file, file_from_url, file_from_path, text |
MultimodalResponse | text, audio, images, videos, files, model, provider, usage, cost_usd, cost_source; has_audio, has_images, is_multimodal, save_all(directory, prefix=...) |
ImageOutput, AudioOutput, VideoOutput, FileOutput | Produced media (url, is_inline, save(path)) |
MediaRouter, MediaProvider, OpenAIMediaProvider, OpenRouterMediaProvider, FalMediaProvider, MiniMaxMediaProvider, default_media_router() | Longest-prefix routing of (model, modality) to a provider: register, set_default, default_model, resolve, describe, providers |
MediaFetcher | Explicit downloads for http(s) media URLs: fetch, download |
CostEntry(model, provider=None, source="llm", operation="chat", input_tokens=0, output_tokens=0, total_tokens=0, cache_read_tokens=0, cache_creation_tokens=0, cost_usd=None, cost_source=None, capability=None, extra={}), CostTracker, execution_cost(ctx=None), use_tracker(tracker=None) | Per-execution accounting; totals(), entries, and total_cost_usd (sum of known prices, None when none are known). Check has_unknown_costs or calls_without_price for incomplete totals |
Harness
| Name | Purpose |
|---|---|
HarnessResult(text, provider="atf-harness", session_id=None, model=None, usage={}, returncode=0, parsed=None, duration_ms=0, turns=0, cost_usd=None, events=[], remote=None) | One harness run; result, is_error, input_tokens, output_tokens, total_tokens |
atfgraph.harness: RemoteHarness(base_url, profile, edge_auth=None, app_token_env=None, model=None, thinking=None, timeout=30.0, poll_interval=2.0, metadata={}), ExistingWorkspace(cwd), RemoteHarnessMetadata, RemoteHarnessClient, RemoteHarnessError, HarnessResetRequired, remote_harness_doctor(transport) | Remote transport for Agent.harness(..., transport=, workspace=): typed HTTP/SSE client, credential-free configuration (edge provider + named token variable), the metadata a remote run attaches as HarnessResult.remote, and the doctor that checks reachability/readiness/profile without a turn. See 07-harness.md. |
HarnessFailure | A failed or interrupted harness invocation, never a fabricated answer |
harness_doctor(providers=None, *, binaries=None), ProviderHealth | Which provider CLIs are installed; looks up executables only, never runs them |
Emitters
| Name | Purpose and methods |
|---|---|
ScheduleTrigger(cron=None, timezone="UTC", every_seconds=None, input={}, code_origin=None) / ScheduleEmitter | Bind a capability to a schedule; to_binding(capability, *, version=None), matches, source |
EventTrigger(source, types=[], secret_env=None, config={}, code_origin=None, transform=None) / EventEmitter | Bind a capability to an authenticated webhook source; matches(source, event_type), to_binding |
Trigger | Union[EventTrigger, ScheduleTrigger] |
on_schedule(cron=None, *, timezone="UTC", every_seconds=None, input=None), on_event(source, *, types=None, secret_env=None, config=None, transform=None) | Decorators staging a trigger on the next registration |
TriggerContext / EmitterContext | ctx.trigger for an emitter delivery: trigger_id, source, event_type, event_id, idempotency_key, received_at, managed_by, vc_id; emitter_id, code_managed, to_dict() |
async simulate_trigger(entry_or_func, *, source, body=None, event_type="", event_id=None, idempotency_key=None, trigger_id=None, received_at=None, managed_by="code") | Run a handler in-process as if an emitter delivery of source had fired |
TransformError | The registered transform rejected or could not process a delivery |
Emitters(client) | Server-side emitter administration: async create(name, target, *, kind=None, source=None, input=None, version=None, interval_seconds=None, cron_expression=None, timezone=None, event_types=None, secret_env=None, source_config=None), list, get, update(emitter_id, *, expected_revision, enabled=None, managed_by=None), delete, events(emitter_id), fire(emitter_id, delivery_key, *, input=None), replay(emitter_id, event_id), sync(label, bindings), metrics; webhook_url(emitter) |
Emitter, InboundEvent | Emitter definition and one received delivery |
Discovery and multi-node
| Name | Purpose and methods |
|---|---|
Discover(client) | Namespace-scoped registry: async agents(), capabilities(*, label=None, version=None, name=None, kind=None, query="", limit=None, offset=0), resolve(target, *, version=None), invoke(target, input=None, *, version=None, timeout=None, **options), publications(*, query=None), publish(label, *, version=None, protocol="http", published=False, display_name=None, description=None), remove_publication(publication_id), settings() |
AgentMesh(client, labels) | The same view restricted to selected labels; callable as mesh(**filters) |
DiscoveredCapability | label, version, capability, target; async submit, invoke pinned to that version |
Publication | A managed descriptor returned by publish |
OfflineMesh(agents, *, title=..., worker_id="offline-mesh", actor_id="offline", propagate_usage=True) | Several nodes in one process behind one ASGI app with an offline graph: async open, aclose, invoke, submit, serve_async; serve, client(), discovery, app, health(), usage(root_id), resolve(node_id), node_ids, is_open, bound_port(). Importable from atfgraph.offline; not in atfgraph.__all__ |
Identity and credentials
| Name | Purpose and methods |
|---|---|
Identity(client) | Server-held Ed25519 node keys and signed paths: async create(label), list(*, label=None), rotate(key_id), revoke(key_id), sign(traverser_id, key_id), proofs(traverser_id), verify(proof) |
NodeIdentity, PathProof, Verification | Key record (id, label, algorithm, public_key, state), signed snapshot (to_dict()), verdict (valid, trusted, key_state, algorithm) |
Credentials(client_provider) | DIDs and W3C credentials: for_client(client); async enroll(label), dids(), did(label, *, web_base_url=None), resolve(did), issue(issuer_label, *, kind=None, traverser_id=None, subject=None, type=None, expires_in_seconds=None, parent_id=None, ctx=None), issue_execution(traverser_id=None, *, issuer_label=None, expires_in_seconds=None, parent_id=None, ctx=None), get(credential_id, *, ctx=None), list(*, issuer_label=None, node_label=None, traverser_id=None, root_id=None, subject_id=None, kind=None, parent_id=None, revoked=None, limit=None), verify(credential, *, at=None, resolve_remote=False, ctx=None), revoke(credential_id, reason=None), tags(*, label=None, state=None), propose_tags(label, tags), decide_tags(label, decision, *, tags=None, reason=None), tag_policy(), set_tag_policy(*, default_mode=None, rules=None, issuer_label=None) |
DidEnrolment, DidResolution, Credential, CredentialPage, CredentialVerification | Results; Credential.subject, Credential.revoked; CredentialVerification.valid, trusted, reason, failed_checks |
TagLedger, TagEntry, TagPolicy, TagProposalResult, TagDecisionResult | Tag ledger types; TagPolicy.mode_for(tag), TagLedger.approved, TagProposalResult.pending. TagRule is in atfgraph.credentials |
Observability
| Name | Purpose and methods |
|---|---|
Observability(client_provider) | for_client(client); async record_usage(entries, *, ctx=None, traverser_id=None), usage(*, traverser_id=None, root_id=None, limit=100, cursor=None, ctx=None), usage_totals(*, since=None, until=None, group_by="run", root_id=None, principal=None, all_principals=False), log(message, level="info", *, stream="app", source="sdk", **fields), append_logs(entries, *, ctx=None, traverser_id=None), query_logs(*, traverser_id=None, root_id=None, levels=None, stream=None, since=None, until=None, after=0, limit=100, contains=None, ctx=None), tail_logs(...), run_metadata(root_id=None, *, ctx=None), set_run_metadata(root_id=None, *, set=None, unset=None, ctx=None), settings(), set_settings(*, node_logs_enabled=None, node_logs_max_message_bytes=None), webhook(), set_webhook(url, *, secret_env=None, headers=None, event_types=None, enabled=True), delete_webhook(), webhook_status(), test_webhook(message=...), redrive_webhook(limit=100) |
UsageReceipt, UsageRecord, UsagePage, UsageReport, UsageTotals | Durable usage results; UsageReport.by_key, UsageTotals.cost_complete, UsageRecord.cost_known |
LogReceipt, LogRecord, LogPage | Node-log results; LogPage.next_cursor |
RunMetadata | root_id, metadata, entries, updated_at; mlflow_trace_id, mlflow_experiment_url |
WebhookConfig, WebhookStatus | Webhook configuration (secret_present, never the secret) and delivery counters |
UsageShipper, NodeLogHandler, UsageReporting | The pieces Agent uses: stable call_ids per attempt; a logging.Handler with pending(), flush_async(), dropped, shipped, failed, last_error; the counters behind Agent.usage_reporting() |
atfgraph.mlflow | Optional module (enable, enable_from_env, disable, trace, span, settings, stats, flush, current_trace_id, trace_headers, join_trace); not part of atfgraph.__all__ |
Controls
| Name | Purpose and methods |
|---|---|
RateLimitPolicy(rate=None, per=1.0, burst=None, concurrency=None, max_pending=100) | rate admissions per per seconds (token bucket of burst tokens) plus a concurrency cap and a bounded waiting queue |
RateLimiter(default=None, *, policies=None, clock=None) | Per-key admission for one event loop: async acquire(key, *, timeout=None), release(key), limit(key, *, timeout=None), async run(key, func, *args, timeout=None, **kwargs), set_policy, policy_for, stats(key), in_flight, pending |
RateLimitExceeded, RateLimitStats | Refusal (queue full or deadline passed) and counters |
ResultCache(*, ttl=300.0, max_size=1024, sweep_interval=30.0, clock=None) | Expiring, size-bounded, single-flight cache: get, set, delete, clear, keys, expires_in, async get_or_compute(key, factory, *, ttl=None), start, async stop(*, clear=False), sweep, in_flight, sweeping |
CacheStats | Cache counters |
ModelRouter(*, limiter=None, admission_timeout=None) | A ModelProvider dispatching to registered providers only: register(name, provider, *, models=(), prefixes=(), default=False, default_model=None, limit_key=None), unregister, resolve(model=None, *, needs=None), async complete, stream, routes, default_route, capabilities |
ProviderRoute | One registered route (name, provider, models, prefixes, default_model, limit_key; matches) |
async retry_rate_limited(func, *, max_attempts=3, base_delay=0.2, max_delay=5.0, deadline=None, sleep=asyncio.sleep, clock=None) | Retry func() on HTTP 429 with capped exponential backoff, honouring retry_after |
Hosting
| Name | Purpose and methods |
|---|---|
Worker, WorkerStats | The outbound worker behind Agent.serve: async enroll, run(stop), drain(timeout=...), abandon_running; stats claimed, succeeded, failed, cancelled, paused, lease_lost, stale_completions, max_concurrent |
ServerlessHost(agent, *, client=None, capacity=None, max_duration=30.0, register=True, sync_emitters=False, claim_interval=0.01, max_idle_interval=0.1, min_heartbeat=0.2, shutdown_grace=1.0), serverless_host(spec_or_agent, **options) | One bounded invocation per event: async handle(event), handle_sync(event), entrypoint(*, safety_margin=1.0), async aclose(*, drain=False), client |
Invocation, ServerlessEventError, ServerlessLoadError | Parsed event (action, capability, input, session_id, idempotency_key, timeout, include_path) and its failures |
RealtimeSession, RealtimeEvent, SessionTurn, SessionDefinition, build_session_definition(...), validate_session_transport(...), RealtimeError, SessionTransportError | Live OpenAI Realtime session: async connect, send_text, append_audio, commit_audio, create_response, cancel_response, send_function_result, events(), turn(), close. validate_session_transport accepts only the transports that work |
Testing
| Name | Purpose |
|---|---|
atfgraph.testing.FakeGraphServer(*, lease_seconds=30.0, api_keys=None, product="ATFGraph vNext", version="0.0.0-fake") | In-memory contract double over httpx.MockTransport for fast SDK unit tests: transport(), client(**kwargs), advance(seconds), fail_next(path_suffix, *, status=500, times=1, method=None), records(*, target=None, root_id=None), count(target). It is not the graph server; see ./15-testing.md for the real-daemon fixture |
atfgraph.testing.serve_agent(agent, server, *, capacity=None) | Async context manager running an agent's worker against the fake |
atfgraph.testing.FakeError, atfgraph.testing.Identity | The fake's error and its token identity (namespace, principal, roles) |
atfgraph.testing.emitter_fixture_sources(), load_emitter_fixture(source) | Packaged emitter delivery fixtures |
Errors
| Name | Raised when |
|---|---|
ATFGraphError | Base class for every SDK error |
APIError | The graph server answered with an error envelope (status, code, message) |
AuthError | 401 or 403 |
NotFoundError | 404 |
ConflictError | 409: immutable definition changed, stale lease, revision mismatch |
ValidationError | 400 or 422 |
TransportError | The HTTP request never produced a response |
TraversalError | A traverser reached a terminal state other than succeeded; subclasses TraversalFailed, TraversalCancelled, TraversalTimedOut |
WaitTimeout | The client-side wait deadline passed before a terminal state |
HandlerError(message, *, code="handler_error", retryable=False), RetryableError(message, *, code="retryable") | Raised from a handler to control the error envelope (to_envelope()); RetryableError is the retryable shorthand |
LeaseLost | The worker no longer holds the lease for a task |
NoExecutionContext | A context-bound operation was used outside a worker task |
ModelNotConfigured | app.ai was called without a configured model provider |
ModelError, MediaError, MediaCapabilityError, MediaProviderNotConfigured | Provider answered badly; media payload unusable; provider cannot do what was asked (no request sent); missing media API key |
EmbeddingError, SemanticIndexError | Embedding provider failed; lexical write succeeded but vector indexing did not finish |
RateLimitExceeded, TransformError, RealtimeError, SessionTransportError, ServerlessEventError, ServerlessLoadError, HarnessFailure | Listed with their groups above |
Next
- ./01-install-and-first-node.md to see the authoring group in use.
- ./15-testing.md for the daemon fixture and the limits of
FakeGraphServer. - ./14-observability.md for the usage, log and metadata types.