Skip to main content

datagoat-decide (Python)

pip install datagoat-decide     # or: uv add datagoat-decide
export DATAGOAT_API_KEY=dg_live_...

Wrap a LangGraph node

from datagoat_decide import Datagoat
dg = Datagoat()  # reads DATAGOAT_API_KEY and DATAGOAT_BASE_URL (your Datagoat deployment URL)

graph.add_node("qualify", dg.wrap("sdr.qualify", qualify_lead,
    input_key="lead", output_key="qualification", case_id="lead_id"))
  • Valid answer → Datagoat's answer goes into state["qualification"], your node does not run.
  • No valid answer → your fallback (set in the dashboard): your node runs as before, or the case goes to a person, or no decision (None).
  • Datagoat unreachable (or past the SDK's budget) → your node runs. Datagoat reachable but its engine down or slow → the outage fallback you set (your node by default). The SDK never blocks your agent past its budget (timeout, default 2.5 s: Datagoat gets 800 ms to answer; the SDK waits 2,500 ms so a call the server already logged never times out on the client). Every call carries an idempotency key, so a call that timed out after Datagoat logged it is replayed off your agent's path and still counted.

When a person decides

If the decision's fallback is Send to a person (or its outage fallback is, during an outage), a case Datagoat has no answer for goes to the dashboard Queue, and the node writes None. Keep the decision id and read the person's answer once it's in:

graph.add_node("qualify", dg.wrap("sdr.qualify", qualify_lead,
    input_key="lead", output_key="qualification", case_id="lead_id",
    on_queued=lambda d, state: save_for_later(state["lead"]["lead_id"], d.decision_id)))

# later, in a worker
s = dg.get_decision(decision_id)            # {"status": "pending" | "resolved" | "final", "answer": {...}}
answer = dg.wait_for_human(decision_id, timeout=600)   # polls; None if nobody answered in time (or the id is unknown)

answer has the same fields as Datagoat's answer (flag, label, choice) plus what the person picked (value) and their note. Async: aget_decision, await_for_human. @dg.point takes on_queued too. With a LangGraph checkpointer you can route a None to a node that calls interrupt(), and resume the run with Command(resume=answer) once the answer is in. The person's answer also goes onto the case, so training sees what was decided; it never counts as your AI's.

Using the decision in later nodes

When you change the steps after a decision (see the handoff on the decision's pattern), later nodes read the decision from the graph state:

class State(TypedDict, total=False):
    lead: dict
    qualification: dict
    datagoat: dict   # {"fit": {...} | None, "steer": bool}

graph.add_node("qualify", dg.wrap("sdr.qualify", qualify_lead,
    input_key="lead", output_key="qualification", case_id="lead_id", decision_key="datagoat"))

def write_outreach(state):
    fit = (state.get("datagoat") or {}).get("fit")
    if fit:
        ...  # new behaviour; branch on ids: any(m["id"] == "c_trial_started" for m in fit["missing"])
    else:
        ...  # exactly the old node

Add the key to your state: LangGraph drops keys it doesn't know without an error. fit is set only when Datagoat answered and the case is in the test group; when it is None, run the node exactly as before (those cases are the unchanged group of the A/B test). Never give fit or the pattern to the node Datagoat wraps. Outside LangGraph, a decorated function gains with_decision(case), which returns (result, decision).

Any function

@dg.point("cs.risk_tier", case_id=lambda acct: acct["account_id"])
def risk_tier(acct: dict) -> dict: ...

Outcomes

# observed_at: when it happened, not when you send it (an outcome only counts for a decision made before it)
dg.outcomes("sdr.qualify", [{"case_id": "L-20419", "value": 1, "observed_at": "2026-10-21T14:02:00Z"}])

Trying the agent out

Set DATAGOAT_TEST=1 (or Datagoat(test=True)) for local runs, CI and checking the wiring. Every call is answered as usual, but Datagoat keeps nothing: a try-out never becomes a case's decision or teaches Datagoat anything, even with a real case id. Results aren't reported and outcomes() sends nothing. Never set it where the agent really runs.

Map your agent

datagoat-decide map my_agent.graph:graph --name "SDR agent"

Metadata

Release files for datagoat-decide 0.6.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 datagoat-decide 0.6.0
File Size Uploaded Provenance
datagoat_decide-0.6.0.tar.gz 172.6 kB Without provenance Details

Built distribution (wheel)

Table of built distributions (wheels) for datagoat-decide 0.6.0
File Interpreter ABI Platform
datagoat_decide-0.6.0-py3-none-any.whl Python 3 none any Details

Total release size: 230.5 kB

Release files / datagoat_decide-0.6.0.tar.gz

Download URL datagoat_decide-0.6.0.tar.gz
Size 172.6 kB
Tags Source
SHA-256 checksum
How to use checksums
2a19b3cd92ac6420685e6f47385e48cf4fad6e5a411e3dcd7e5aa0a2626e61f4
BLAKE2b-256 checksum
How to use checksums
8f1b3262ef8b81c377323e9cfbfa1493eb0a8b85db0255c986385264d9a4a9a0
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via uv/0.12.0 {"installer":{"name":"uv","version":"0.12.0","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":null,"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":null}

Release files / datagoat_decide-0.6.0-py3-none-any.whl

Download URL datagoat_decide-0.6.0-py3-none-any.whl
Size 57.9 kB
Tags Python 3
SHA-256 checksum
How to use checksums
0c37b0cbfcc403894f23d1903e9e5d4a161db1b4cbf475fcd36347e738504452
BLAKE2b-256 checksum
How to use checksums
a3c1b3da7d3193029b404ba5a64de8bc680891bf5216e83d102404af985900c9
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via uv/0.12.0 {"installer":{"name":"uv","version":"0.12.0","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":null,"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":null}

Security for datagoat-decide 0.6.0

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.

No provenance found

None of the files in this release were uploaded with provenance metadata.

A note on package security

PyPI is a repository for distributing packages, not a service for auditing them. While third-party security researchers and our staff do their best to detect and remove malicious packages, PyPI cannot guarantee the quality, security or suitability of any given package.

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