Skip to main content

The safest way to build agentic AI — a full-stack, open-source agent SDK where control is native: a cognitive router picks the shape, GSAR grounds every claim, and every risky action must clear an admission gate. Proven first in the security domain.

Project description

tuliplabs

Tulip — an open-source agentic harness: agents that act, on a runtime where every consequential action clears your policy, waits for a person when it matters, and lands on a record you can prove.
A full-stack agent SDK — tools, memory, multi-agent, RAG — on a runtime where control is native. The cognitive router picks the shape, GSAR (typed grounding — every claim must trace to evidence, or the agent abstains) checks what gets asserted, and the admission gate runs a consequential action only if your policy allows. Safe by construction, not by reminder.

PyPI version Python 3.11–3.14 License: Apache 2.0 mypy strict ruff clean

OpenAI · Anthropic · bring your own
A model is one string. The loop, the tools, and the event stream stay put.

Why Tulip · Cognitive router · GSAR grounding · Admission gate · Notebooks · Workbench


Build an agent

A model is a string, a tool is a function, and run_sync runs the loop. That's the whole surface for your first agent.

from tulip import Agent, tool

@tool
def search_flights(origin: str, destination: str, date: str) -> list[dict]:
    """Find available flights between two cities on a given date."""
    return flights.search(origin, destination, date)

agent = Agent(
    model="anthropic:claude-sonnet-4-6",          # swap providers with one string
    tools=[search_flights],
    system_prompt="You are a travel assistant. Be concise and cite prices.",
)

print(agent.run_sync("Cheapest flight from Lisbon to Berlin next Friday?").text)

Behind the scenes the agent alternates reasoning with tool calls until it can answer. The model call, retries, and tool dispatch all live behind that one Agent class — point model= at "openai:gpt-4o" and nothing else moves.

pip install "tulip-agents[anthropic]"     # or [openai], or [sdk] for everything

No mandatory cloud account to start — a bundled MockModel lets every notebook run offline.


What is Tulip?

Tulip is a full-stack, open-source agentic harness — an SDK and runtime for agents that take real actions, where control lives in the runtime, not the prompt. You get everything you'd expect: one Agent class, tools, durable memory, RAG, eight multi-agent shapes, streaming, and a typed event stream. Control isn't a guardrail you remember to add — it's wired through three points in the core:

  • The router controls which shape runs. Describe a task in plain language; the cognitive router (PRISM, the router's classifier) fills a typed GoalFrame and a deterministic picker compiles it to the right runtime shape. The model classifies — it never authors the topology.
  • GSAR controls what gets asserted. Every claim is partitioned grounded / ungrounded / contradicted / complementary against typed evidence. Below threshold the agent regenerates, replans, or abstains — an ungrounded claim is a false result by construction and never ships.
  • The admission gate controls what actions fire. A consequential action — issue a refund, ship a deploy, change an account, delete a customer record — runs only after it clears admit(): a policy check outside the model, held for a human when the stakes warrant, recorded on a tamper-evident trail either way.

A model can always be talked into something. The admission check is real code outside the model — so even a confused or misled agent cannot fire an action your policy denies. Try it: examples/can_you_make_it_go_rogue.py.

See it in 60 seconds

Run What it shows
examples/notebook_06_basic_agent.py Your first agent — one Agent, one tool, the run loop.
examples/notebook_58_cognitive_router.py One natural-language task → the router compiles the right shape.
examples/can_you_make_it_go_rogue.py Mislead an agent that holds live production tools — the gate still refuses the action.

Add a tool

A tool is an ordinary Python function — @tool publishes its signature and docstring so the model knows when to reach for it.

from tulip import Agent, tool

@tool
def order_status(order_id: str) -> str:
    """Look up the current status of a customer order."""
    return orders.get(order_id)

agent = Agent(
    model="openai:gpt-4o",
    tools=[order_status],
    system_prompt="You are a helpful support assistant. Be concise.",
)

print(agent.run_sync("Where's my order ord-4821?").text)

For tools where a duplicate call would hurt — moving money, paging an on-call, filing a ticket — declare @tool(idempotent=True): the loop keys every invocation on (name, args) and refuses to fire the same one twice, even across retries.


Talk to any provider

A model is a string. The prefix before the colon (openai:, anthropic:) tells the SDK which provider to use; the rest is the model id that provider expects. get_model() parses the string and returns a ready client.

Agent(model="openai:gpt-4o")                     # OpenAI direct
Agent(model="anthropic:claude-sonnet-4-6")       # Anthropic direct
Provider Class What it covers
OpenAI OpenAIModel Chat completions, reasoning models (o-series), base_url override for Azure · Portkey · LiteLLM · vLLM · together.ai · fireworks · groq
Anthropic AnthropicModel Claude family with prompt caching + extended thinking
Custom register_provider("myco", MyModel) Implement ModelProtocolcomplete · stream (~50 lines)

Because OpenAI-compatible endpoints accept a base_url, OpenAIModel also fronts gateways and self-hosted servers (LiteLLM, vLLM, Azure OpenAI, together.ai, groq, …) without a dedicated provider.

Model providers concept page


The cognitive router (PRISM) — describe what you need, get the right shape

Once you know agents, the next step is knowing which shape to use. The cognitive router takes a natural-language task, runs an LLM classifier that fills a typed GoalFrame (intent · domain · complexity · risk), matches it to one of eight built-in coordination protocols, and the CognitiveCompiler emits the matching runtime primitive — without you hand-coding the topology. The model classifies; routing is deterministic.

from tulip import Agent
from tulip.models import get_model
from tulip.router import (
    CapabilityIndex, CognitiveCompiler, GoalFrame, PolicyGate,
    ProtocolRegistry, Router, SkillIndex, builtin_protocols,
)
from tulip.tools.registry import create_registry

registry = create_registry(kb_search, get_metric, list_alerts)

protocols = ProtocolRegistry()
for p in builtin_protocols():
    protocols.register(p)

router = Router(
    frame_extractor=Agent(model=get_model(), output_schema=GoalFrame),
    protocols=protocols,
    capabilities=CapabilityIndex(registry),
    skills=SkillIndex(),
    gate=PolicyGate(),
    compiler=CognitiveCompiler(),
)

result = await router.dispatch(
    "We just got a sev-1 latency alert on the checkout service. "
    "Investigate and recommend remediation."
)
print(f"protocol={result.protocol_id}")
print(result.text)

The same router.dispatch(...) resolves a one-shot lookup to a single Agent, a multi-step investigation to a SequentialPipeline of planner→executor→validator, and a write-affecting action to an approval-gated agent — chosen by protocol selection, not by the model.

Protocol Compiled shape Best for
direct_response Single Agent ANSWER, EXPLAIN
plan_execute_validate SequentialPipeline (planner → executor → validator) PLAN, BUILD, MODIFY
specialist_fanout ParallelPipeline of N tool-bound Agents DIAGNOSE, MONITOR
debate Two debaters + judge Agent COMPARE
codegen_test_validate LoopAgent (stops on PASS) GENERATE_CODE
approval_gated_execution Agent wrapped in approval interrupt ESCALATE, REMEDIATE
handoff_chain SequentialPipeline of one-tool Agents COORDINATE
a2a_delegate Cross-process agent-to-agent (A2A) call (opt-in) distributed meshes

Cognitive router concept


Multi-agent workflows

When one agent isn't enough, Tulip ships every orchestration shape as a first-class primitive: sequential pipeline, parallel fan-out, refinement loop, explicit state graph, orchestrator + specialists, swarm, handoff chain, and a cross-process A2A mesh. All of them use the same Agent class and the same event stream.

Pattern When to use
SequentialPipeline A → B → C in order; each output feeds the next
ParallelPipeline Fan out to N agents simultaneously, merge results
LoopAgent Refine until a condition fires (PASS/FAIL, confidence, iteration cap)
Orchestrator + Specialists One coordinator routes to domain experts in parallel
Swarm Open-ended work; peers share a task queue and context
Handoff Escalation desk; conversation moves with full history to the next specialist
StateGraph Explicit DAG with conditional edges, cycles, and human-in-the-loop gates
A2A Cross-process meshes over HTTP; agents advertise capabilities via AgentCard
from tulip.agent import Agent, SequentialPipeline

draft    = Agent(model=model, system_prompt="Draft a first answer from the request.")
check    = Agent(model=model, system_prompt="Find weaknesses; cite what's missing.")
finalize = Agent(model=model, system_prompt="Write the final answer, addressing the gaps.")

result = await SequentialPipeline(agents=[draft, check, finalize]).run(
    "Summarize the trade-offs of moving the checkout service to a queue."
)
print(result.text)

All patterns


Grounded by construction (GSAR)

An agent that acts must not assert what it can't back up. Tulip's GSAR layer (paper) partitions every claim — grounded / ungrounded / contradicted / complementary — against typed evidence, where tool output outranks inference and inference outranks domain priors. Below threshold the run regenerates, replans, or abstains. There is no public constructor that emits a grounded result without a score, so an ungrounded claim is unshippable by construction — not filtered after the fact.

Shown here through tulip.security, one domain application of the contract — the same partition types back any grounded result.

from tulip.reasoning.gsar import Claim, EvidenceType, Partition
from tulip.security import ground_finding, Severity, is_finding

result = ground_finding(
    title="Expired TLS certificate on 192.0.2.10:443",
    description="Serving endpoint presents an expired certificate.",
    severity=Severity.HIGH,
    asset="192.0.2.10:443",
    remediation="Rotate the certificate; enforce automated renewal.",
    partition=Partition(grounded=[
        Claim(text="cert expired 2026-05-30", type=EvidenceType.TOOL_MATCH,
              evidence_refs=["tool:tls_scan:not_after=2026-05-30"]),
    ]),
)
# A grounded partition → a typed result. An ungrounded one → an auditable
# Abstention with the reason it was withheld. There is no third path.
print(result.title if is_finding(result) else f"withheld: {result.reason}")

GSAR grounding


The admission gate — an action runs only if policy allows

The moment an agent stops advising and starts acting, a wrong step becomes a real consequence. A prompt rule is advisory — a misleading input or an injected document can talk the model past it. Tulip makes the rule structural: the side-effecting call runs only after it clears admit(), a gate the model has no way to reach around.

from tulip.control import Action, AuditTrail, ControlPolicy, admit, AdmissionError

policy = ControlPolicy(require_human_for={"production"})
trail = AuditTrail()

async def safe_refund(order_id: str, usd: float):
    try:
        return await admit(
            Action(name="refund", asset=order_id, kind="payment", environment="production"),
            lambda: payments.refund(order_id, usd),     # your code — any agent loop
            policy=policy, trail=trail,
        )
    except AdmissionError as e:
        notify_oncall(e.decision)                       # the gate held it; the trail has it

Production payments now require a human, and the attempt is recorded either way:

action → policy → approval → admission → audit

  • Policy + approvalapprove() weighs your ControlPolicy (blast radius, require_human_for, verification score) and returns allow, hold, or deny.
  • Admissionadmit() runs the action only if approval allows, recording the decision to the AuditTrail; otherwise it raises AdmissionError.
  • Audit — every entry is linked to the one before it, so editing any record breaks verify(). (A keyless SHA-256 chain: tamper-evident, not notarized — add signing before treating it as legally authoritative.)

Human approvals are durable: require_human_for pauses the run, and an interrupt() + checkpointer means the decision survives a restart and the run resumes where it left off.

The admission gate


Govern agents you already run

You don't have to build on Tulip to be governed by it. tulip-frameworks wraps a tool from the framework you already use — LangChain, LangGraph, CrewAI, the OpenAI Agents SDK, LlamaIndex, or Google ADK — with the same admit() gate and hash-chained AuditTrail, in about three lines, no rebuild:

pip install "tulip-frameworks[langchain]"   # or [crewai] / [openai-agents] / [llama-index] / [adk] / [all]

Agents outside Python reach the same gate over the wire through tulip-gateway's /v1/admit with the TypeScript client (tulip-frameworks-js). See the frameworks guide.

And governed_agent() gives any Tulip agent the full harness — grounded, guarded, risk-gated, audited — in one call:

from tulip.control import governed_agent

secured = governed_agent(model="openai:gpt-4o", tools=[...])
assert secured.audit_trail.verify()   # the chain is intact — no record was altered

What you get

Build — the agent framework surface:

🧭 Cognitive router Describe a task → eight named protocols → the right primitive compiled automatically. The LLM fills a typed schema; routing is deterministic.
🤝 Multi-agent Seven native patterns + cross-process A2A. One Agent class. One event stream.
🔬 DeepAgent create_deepagent (single agent, per-turn grounding) and create_research_workflow (StateGraph with post-hoc grounding eval + two-level recovery).
🪙 MCP MCPClient consumes MCP (Model Context Protocol) servers. TulipMCPServer exposes the SDK's tools as MCP.
🌐 Multi-modal Agent(web_search=…, web_fetch=…, image_generator=…, speech_provider=…) auto-registers tools.

Control — the runtime that clears actions:

⚖️ Admission gate admit() / approve() run a consequential action only if your ControlPolicy allows — else hold for a human or deny, recorded either way.
🧠 GSAR grounding Claims partitioned grounded / ungrounded / contradicted / complementary; below threshold the agent regenerates, replans, or abstains. arXiv:2604.23366.
🔁 Idempotent tools @tool(idempotent=True) — dedupes on (name, args). The model can't double-charge, double-book, or double-page.
🪝 Hooks Logging · OpenTelemetry · ModelRetry · Guardrails · Steering (LLM-as-judge).

Run — operate it in production:

📡 Observability Opt-in EventBus — one run_context() streams 40+ canonical events from every layer, no external broker. TelemetryHook for OpenTelemetry/OTLP.
💾 Durable memory 8 checkpoint backends — PostgreSQL · MySQL · Redis · OpenSearch · S3 / MinIO / R2 · in-memory · file · HTTP.
🧠 Long-term memory Mem0MemoryManager over mem0. Portable path: LLMMemoryManager over any BaseStore (InMemory / Redis / Postgres / OpenSearch).
🔎 RAG 5 vector stores — pgvector · Qdrant · Chroma · OpenSearch · in-memory. OpenAI + Cohere embeddings · local + Cohere rerankers · multimodal (PDF, image OCR, audio).
📡 Streaming + Server Typed events · SSE · AgentServer (FastAPI, single shared-key bearer auth, thread persistence).
📊 Evaluation EvalCase / EvalRunner / EvalReport regression suites.

Inside the SDK — the stack, not just the loop

A Tulip agent isn't a one-shot ReAct loop. The same Agent class runs inside eight orchestration shapes, chosen automatically by the PRISM cognitive router from a natural-language task, with typed reasoning around every Execute and a pluggable, vendor-neutral backend stack. The agent loop is the inner engine — the SDK is the whole stack around it.

The SDK stack — the PRISM cognitive router compiles natural-language tasks into one of 8 orchestration shapes, each of which runs the agent loop (Think → Execute → Reflect → Terminate), powered by foundations (Models, Memory, RAG, Observability, Tools/MCP/Skills)

Every node at every layer emits a write-protected typed event — the same stream powers SSE, telemetry hooks, and your own async for event in agent.run(…) consumer.


Vendor-neutral backends

RAG, memory, and persistence are defined by small contracts in tulip.rag and tulip.memory — pick any backend that implements them. Nothing is wired to a single vendor, and most have a free/local test path (in-memory Qdrant, embedded Chroma, MinIO via moto, an offline cross-encoder reranker).

from tulip.rag import OpenAIEmbeddings, QdrantVectorStore, RAGRetriever
from tulip.rag.reranker import CrossEncoderReranker

retriever = RAGRetriever(
    embedder=OpenAIEmbeddings(model="text-embedding-3-small"),
    store=QdrantVectorStore(location=":memory:", dimension=1536),  # or a server URL
    reranker=CrossEncoderReranker(top_n=5),                        # local, offline
)
await retriever.add_documents(corpus)
hits = await retriever.retrieve("…", limit=5)
Capability Backends
Vector stores (tulip.rag.stores) PgVectorStore · QdrantVectorStore · ChromaVectorStore · OpenSearchVectorStore · InMemoryVectorStore
Embeddings (tulip.rag.embeddings) OpenAIEmbeddings · CohereEmbeddings
Rerankers (tulip.rag.reranker) CrossEncoderReranker (local sentence-transformers) · CohereReranker (Cohere API)
Checkpointers (tulip.memory.backends) RedisBackend · PostgreSQLBackend · MySQLBackend · OpenSearchBackend · S3Backend (AWS S3 / MinIO / R2) · FileCheckpointer · MemoryCheckpointer · HTTPCheckpointer
Long-term memory (tulip.memory.managers) Mem0MemoryManager (mem0) · LLMMemoryManager over any BaseStore

Every backend is an optional extra — install only what you use (pip install "tulip-agents[qdrant,s3,rerank-local]").


Install

pip install "tulip-agents[openai]"        # OpenAI
pip install "tulip-agents[anthropic]"     # Anthropic
pip install "tulip-agents[rag]"           # vector stores + embeddings + rerankers
pip install "tulip-agents[sdk]"           # everything

Quickstart guide


Any domain, one contract

The same contracts run wherever an agent acts — a support desk approving concessions, a payments team settling disputes, an infra team gating deploys. One fully worked domain package ships today: tulip.security applies the grounded-evidence contract to red-teaming — systematically probing — AI systems: every result is a grounded Evidence, tagged against public weakness catalogues (MITRE ATLAS, OWASP LLM / Agentic Top 10), or an explicit Abstention:

from tulip.security import Target, red_team, is_finding

report = await red_team(Target.endpoint("https://support-bot.example/chat"), suite="owasp-asi")
for r in report:
    print(r.title if is_finding(r) else f"abstained: {r.reason}")

Vendor-specific adapters (Splunk, CrowdStrike, Okta, Auth0, VirusTotal, Wiz, RunPod, Lambda) live in the community package tulip-integrations (pip install "tulip-integrations[edr-crowdstrike]") — core ships offline reference adapters so the SDK runs standalone. Not to be confused with tulip.integrations (this repo), the built-in MCP client/server.


Built on Tulip

Tulip is the open-source foundation; Tulip Labs builds its commercial products on top of this same SDK. Everything in this repository is Apache-2.0 and usable on its own — the SDK is the product surface, not a teaser for it.


Notebooks

examples/ has a set of progressive notebooks, numbered in suggested reading order. Each one defaults to a bundled mock model when no API key is present, so every example runs offline with no credentials; set OPENAI_API_KEY to run them against a real provider.

git clone https://github.com/tuliplabs-ai/sdk-python.git
cd sdk-python && pip install -e .

python examples/notebook_06_basic_agent.py           # your first agent
python examples/notebook_58_cognitive_router.py      # the cognitive router
python examples/notebook_69_research_workflow.py     # full research pipeline
Track What you learn
Agent Foundations Agent, tools, memory, streaming, hooks, termination
Graphs & composition StateGraph, conditional routing, reducers, human-in-the-loop (HITL), composition, functional API
Multi-agent Swarm, handoff, orchestrator, A2A, DeepAgent, debate, emergent routing
Reasoning & structured Pydantic schemas, reasoning patterns, GSAR typed grounding
RAG Basics, vector stores, embeddings, rerankers, RAG agents
Skills, playbooks, plugins MCP, playbooks, plugins, skills, steering
Production Guardrails, checkpoints, evaluation, providers, multi-modal
Cognitive router + observability Routing, EventBus, yield bridge, event catalogue
Real-world workflows Incident response, vendor review, DPA review, spoken advisories
Server & full pipelines Agent server (FastAPI), full research workflow

Full notebooks index


Workbench

A browser-based playground for every SDK pattern. Two clicks to a running agent — no CLI install, no editor setup. Three model slots (A / B / C) so multi-agent notebooks can mix a fast triage model with a deeper specialist. It lives in its own repo — tuliplabs-ai/workbench.

git clone https://github.com/tuliplabs-ai/workbench.git && cd workbench

# Three terminals, one per tier (the python tier is hatch-managed):
cd backend && hatch run sdk && hatch run serve   # FastAPI runner on :8100
cd bff     && npm install && npm run dev         # BFF on :3101
cd web     && npm install && npm run dev         # Vite on :5173

Or in Docker:

docker build -t tulip-workbench . && docker run --rm -p 5173:5173 -p 3101:3101 -p 8100:8100 tulip-workbench
# open http://localhost:5173

→ Full walkthrough: Workbench guide


Deploy

pip install "tulip-agents[server,openai]"

AgentServer is a drop-in FastAPI app: POST /invoke, POST /stream, GET/DELETE /threads/{id}, GET /health.

from tulip.server import AgentServer

server = AgentServer(agent=my_agent, api_key=os.environ["API_KEY"])
server.run(host="0.0.0.0", port=8080)

The repo ships a multi-stage Dockerfile ready to drop into your own image pipeline. Deploy anywhere FastAPI runs — Kubernetes, ECS / Fargate, Cloud Run, Fly.io, a plain VM.

Deploy guide


Repo layout

src/tulip/
├── agent/          Agent runtime, config, SequentialPipeline / ParallelPipeline / LoopAgent
├── core/           AgentState, Message, events, termination algebra, Send
├── loop/           ReAct nodes (Think, Execute, Reflect)
├── router/         Cognitive router — GoalFrame, ProtocolRegistry, PolicyGate, CognitiveCompiler
├── control/        Admission gate — Action, admit/approve, ControlPolicy, AuditTrail
├── deepagent/      create_deepagent + create_research_workflow + 6 node primitives
├── observability/  EventBus, run_context, agent yield bridge, EV_* constants
├── memory/         BaseCheckpointer + 8 backends
├── models/         Provider registry + OpenAI, Anthropic
├── multiagent/     Orchestrator, Swarm, Handoff, StateGraph, Functional
├── a2a/            Cross-process Agent-to-Agent protocol
├── reasoning/      Reflexion, Grounding, Causal, GSAR
├── rag/            Embeddings + 5 vector stores + rerankers + retrievers
├── providers/      Multi-modal: web search, web fetch, image, speech
├── tools/          @tool decorator, registry, builtins, executors
├── hooks/          Logging, telemetry, retry, guardrails, steering
├── skills/         AgentSkills.io filesystem-first capability disclosure
├── playbooks/      Declarative step plans + PlaybookEnforcer
├── security/       Grounded findings, red-team / assure, taxonomy tags
├── server/         FastAPI AgentServer with thread persistence
├── evaluation/     EvalCase + EvalRunner + EvalReport
└── integrations/   MCP (client + server)

examples/           Progressive notebooks, each a single runnable file.
tests/unit/         Deterministic, no external deps. Runs in CI on every PR.
tests/integration/  Live OpenAI / Anthropic. Gated on credentials.

The documentation site and the browser workbench live in sibling repos: tuliplabs-ai/docs (published at tulipagents.ai) and tuliplabs-ai/workbench.


Contributing

git clone https://github.com/tuliplabs-ai/sdk-python.git
cd sdk-python && pip install -e ".[dev,sdk]"
hatch run check        # ruff + mypy
hatch run test         # unit tests across Python 3.11–3.14
pre-commit install

See CONTRIBUTING.md. Every PR runs format, lint, mypy, unit tests, DCO sign-off.


Citing GSAR

Paper: GSAR: Typed Grounding for Hallucination Detection and Recovery in Multi-Agent LLMs (PDF), 2026.

@article{gsar2026,
  title   = {GSAR: Typed Grounding for Hallucination Detection and Recovery in Multi-Agent LLMs},
  journal = {arXiv preprint arXiv:2604.23366},
  year    = {2026},
  url     = {https://arxiv.org/abs/2604.23366},
}

Security

Please consult the security guide for our responsible security vulnerability disclosure process.


License

Copyright 2026 Tulip Labs.

Released under the Apache License, Version 2.0 — see LICENSE and NOTICE. Full text at https://www.apache.org/licenses/LICENSE-2.0.

Tulip began as a fork of an earlier project released under the Universal Permissive License v1.0 (UPL-1.0); those original portions remain available under the UPL-1.0, while all new contributions are licensed under Apache-2.0. See NOTICE for details.

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

tulip_agents-2.3.0.tar.gz (1.1 MB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

tulip_agents-2.3.0-py3-none-any.whl (646.0 kB view details)

Uploaded Python 3

File details

Details for the file tulip_agents-2.3.0.tar.gz.

File metadata

  • Download URL: tulip_agents-2.3.0.tar.gz
  • Upload date:
  • Size: 1.1 MB
  • Tags: Source
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/6.1.0 CPython/3.13.13

File hashes

Hashes for tulip_agents-2.3.0.tar.gz
Algorithm Hash digest
SHA256 606209669110912059407fde41dc2e62d96a172e6dad1909f42602215dae3488
MD5 bcef94ffada25407d59003a345cfc806
BLAKE2b-256 964c1d309b76f8501b97180fc35595f63ac742823436af357caae1a8b798c9ad

See more details on using hashes here.

Provenance

The following attestation bundles were made for tulip_agents-2.3.0.tar.gz:

Publisher: _release.yml on tuliplabs-ai/sdk-python

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

Details for the file tulip_agents-2.3.0-py3-none-any.whl.

File metadata

  • Download URL: tulip_agents-2.3.0-py3-none-any.whl
  • Upload date:
  • Size: 646.0 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/6.1.0 CPython/3.13.13

File hashes

Hashes for tulip_agents-2.3.0-py3-none-any.whl
Algorithm Hash digest
SHA256 2c9c98818afa3d96bb8ee6bab78b3032b1a91f55d0f51a869974b86daa6f3df0
MD5 47fe2069573759b1922af01f0beecba0
BLAKE2b-256 c82d8e15e349098eb9fdec7e864d9c611ad6021019a8c652f3851b3ca17f7187

See more details on using hashes here.

Provenance

The following attestation bundles were made for tulip_agents-2.3.0-py3-none-any.whl:

Publisher: _release.yml on tuliplabs-ai/sdk-python

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page