Python SDK
Use the Python builder to register endpoints, serve Step handlers, and start or inspect Flows.
Installation
pip install argyll-sdk
Client
from argyll import Client
client = Client("http://localhost:8080")
Register a Script Step
from argyll import Client, AttributeType, ScriptConfig, ScriptLanguage
client = Client("http://localhost:8080")
client.new_step() \
.with_id("price-calculator") \
.with_name("Price Calculator") \
.required("quantity", AttributeType.NUMBER) \
.required("unit_price", AttributeType.NUMBER) \
.output("total", AttributeType.NUMBER) \
.with_script(ScriptConfig(
language=ScriptLanguage.LUA,
script="return {total = quantity * unit_price}",
)) \
.register()
Executable Script Steps use Lua. ScriptLanguage.JPATH identifies JSONPath for predicates and attribute mappings, not executable Script Steps.
Serve a Sync Step
start() registers the Step and runs an HTTP server that handles invocations:
from argyll import Client, StepContext, AttributeType
client = Client("http://localhost:8080")
def handle_greeting(ctx: StepContext, args: dict) -> dict:
name = args.get("name", "World")
return {"greeting": f"Hello, {name}!"}
client.new_step() \
.with_id("greet") \
.with_name("Greet") \
.required("name", AttributeType.STRING) \
.output("greeting", AttributeType.STRING) \
.start(handle_greeting)
Serve an Async Step
import threading
from argyll import AsyncContext, AttributeType, Client, StepContext
client = Client("http://localhost:8080")
def handle_process(ctx: StepContext, args: dict) -> dict:
async_ctx = AsyncContext(context=ctx, webhook_url=ctx.metadata["webhook_url"])
def background():
result = do_long_work(args)
async_ctx.success({"result": result})
threading.Thread(target=background).start()
return {} # return immediately
client.new_step() \
.with_id("process") \
.with_name("Process") \
.with_async_invoke() \
.required("input", AttributeType.OBJECT) \
.output("result", AttributeType.OBJECT) \
.start(handle_process)
Serve a Step with Compensation
Use with_compensate_handler to register a handler that undoes a completed Work Item. start() generates the compensation URL:
def handle_charge(ctx: StepContext, args: dict) -> dict:
charge_id = process_charge(args["amount"])
return {"charge_id": charge_id}
def handle_compensate(ctx: StepContext, args: dict) -> None:
refund_charge(args["charge_id"])
client.new_step() \
.with_id("charge-card") \
.with_name("Charge Card") \
.required("amount", AttributeType.NUMBER) \
.output("charge_id", AttributeType.STRING) \
.compensated("charge_id") \
.with_compensate_handler(handle_compensate) \
.start(handle_charge)
The compensation handler receives a flat argument dictionary containing the selected Attributes under their invocation names. Raise WorkNotCompletedError to request another attempt, or another exception to report permanent failure.
Builder Methods
Identity
with_id(id),with_name(name),with_description(text), andwith_tags(*tags), which merges into the Step’s tag set, sorted and deduped
Attributes
required(name, type): required inputoptional(name, type, default): optional input with default valueconst(name, type, value): a fixed value baked into the Step definitionmeta(name, meta_key): a named metadata field (e.g.flow_id,webhook_url) injected at execution timeoutput(name, type): output attributewith_for_each(name): mark an input for parallel expansion over its collected values, requiring acollectpolicy ofallorsomecompensated(*names): include Attributes in compensation requests
Execution Type
with_script(...)selects Script execution
Action Mode
with_invoke_mode(ActionMode),with_compensate_mode(ActionMode): set how an action reports its result,ActionMode.SYNC(default) orActionMode.ASYNCwith_sync_invoke(),with_async_invoke(): shorthand for the invoke action’s mode
HTTP
with_endpoint(url),with_method(method),with_timeout(ms),with_health_check(url)with_compensate(url): set the endpoint URL and compensated handlingwith_compensate_method(method): compensate HTTP method, defaults toPOSTwith_compensate_timeout(ms): compensate timeout, defaults to the Step timeoutwith_compensate_handler(handler): register a compensation handler (auto-generates the URL when used withstart())
Script
with_script(ScriptConfig(...))- executable Script Steps use Lua
Predicate
with_predicate(ScriptConfig(...))- predicates may use Lua or JSONPath (ScriptLanguage.JPATH)
Behavior
with_handling(Handling): choose standard, memoized, or compensated handlingwith_flow_goals(Goals(...)): configure a Flow-type Step with a chain of fallback Goal setswith_flow_space(space_id): restrict its child flow to a Space
Lifecycle
register(): register or update the Step definition, retrying transient failuresstart(handler): register or update with retries, then serve
List Steps
steps = client.list_steps()
Start a Flow
Use with_goals(Goals(...)) to set the chain of fallback Goal sets at once, or with_goal(id) to add a Goal to the last set in the chain. else_ carries a trailing underscore because else is a Python keyword:
from argyll import Client, Goals
client = Client("http://localhost:8080")
client.new_flow("order-123") \
.with_goals(Goals(
steps=["send-confirmation"],
else_=Goals(steps=["queue-confirmation"]),
)) \
.with_initial_state({
"customer_id": ["cust-456"],
"order_amount": [99.99],
}) \
.start()
Initial values are arrays. Wrap each value in a list. Each key declares the resolved values for that Attribute, so an empty list declares zero values and an omitted key leaves the Attribute to providers. See Initial Values Are Authoritative.
Query Flow State
flow = client.flow("order-123")
state = flow.get_state()
Imports
from argyll import (
Client, StepBuilder, FlowBuilder, FlowClient,
StepContext, AsyncContext,
AttributeType, AttributeRole, InputCollect,
ActionMode, BackoffType, Handling, ScriptLanguage,
)
from argyll.errors import (
ArgyllError, ClientError, HTTPError, StepRegistrationError,
StepValidationError, FlowError, WebhookError,
)