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.1

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.1
File Size Uploaded Provenance
datagoat_decide-0.6.1.tar.gz 172.6 kB Without provenance Details

Built distribution (wheel)

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

Total release size: 230.5 kB

Release files / datagoat_decide-0.6.1.tar.gz

Download URL datagoat_decide-0.6.1.tar.gz
Size 172.6 kB
Tags Source
SHA-256 checksum
How to use checksums
1943a8941f25284c034ab2f9531b388a7d4fe9c91a1a80c777f47900ce817950
BLAKE2b-256 checksum
How to use checksums
4598098539ee531f14ef1e0b6b71e451d80587e289aae72bcd554bdd0df71889
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.1-py3-none-any.whl

Download URL datagoat_decide-0.6.1-py3-none-any.whl
Size 57.9 kB
Tags Python 3
SHA-256 checksum
How to use checksums
00280223f662f52fefd161cb09bc3f5f224903e95eca4dd15228a549430a92f9
BLAKE2b-256 checksum
How to use checksums
82cb9f5661c5f736c5367f916501145394e21ee05f020c1aa581e8196ddd9171
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.1

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