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
Tulip — the safest way to build agentic AI.
An open-source, full-stack agent SDK — tools, memory, multi-agent, RAG — on a runtime
where control is native: the cognitive router picks the shape,
GSAR grounds every claim or the agent abstains, and the admission gate runs a
consequential action only if your policy allows. Safe by construction, not by reminder.
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 framework — the safest way to build agentic AI.
You get everything you'd expect: one Agent class, tools, durable memory, RAG, eight
multi-agent shapes, streaming, and a typed event stream. What makes it safe is that
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
PRISM cognitive router fills a typed
GoalFrameand 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, isolate a host — 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.
You can fool the model; you can't talk past the gate. The admission check is real code, outside the model — so even a jailbroken or misled agent can't fire a side-effecting call your policy denies. Try it:
examples/can_you_make_it_go_rogue.py.
No matter how capable a model gets, it structurally cannot prove it won't take a catastrophic action. That's not an intelligence problem; it's a control problem, and control is the layer Tulip owns.
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 |
Jailbreak an agent with live prod tools — the admission gate blocks the action anyway. |
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 ModelProtocol — complete · 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 A2A call (opt-in) | distributed meshes |
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)
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.
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}")
Grounding is what makes an agent safe to let act anywhere claims drive consequences — it is sharpest in security (below), but the contract is domain-neutral.
The admission gate — an action runs only if policy allows
The moment an agent stops advising and starts acting — moving money, deleting a
resource, disabling an account — a wrong step stops being a bad sentence and becomes a real
consequence. A rule in the prompt is advisory by definition; a jailbreak, an injected
document, or a confused chain talks 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, the attempt is recorded whether it ran or not, and your agent keeps working unchanged. The chain is short and every link is real:
action → policy → approval → admission → audit
- Policy + approval —
approve()weighs yourControlPolicy(blast radius,require_human_for, and — when you have it — a grounding/verification score) and returns allow, hold, or deny. - Admission —
admit()runs the action only if approval allows, recording the decision to theAuditTrail; otherwise it raisesAdmissionError. The model never touches this step. - Audit — the trail is hash-chained, so
verify()catches any edit after the fact. (It's a keyless in-memory SHA-256 chain: tamper-evident, not notarized — add signing or an external anchor 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.
What you get
| 🧭 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. |
| 🛡 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. |
| 🔬 DeepAgent | create_deepagent (single agent, per-turn grounding) and create_research_workflow (StateGraph with post-hoc grounding eval + two-level recovery). |
| 📡 Observability | Opt-in EventBus — one run_context() streams 40+ canonical events from every layer, no external broker. TelemetryHook for OpenTelemetry/OTLP. |
| 🛡 Idempotent tools | @tool(idempotent=True) — dedupes on (name, args). The model can't double-charge, double-book, or double-page. |
| 💾 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). |
| 🪝 Hooks | Logging · OpenTelemetry · ModelRetry · Guardrails · Steering (LLM-as-judge). |
| 🪙 MCP | MCPClient consumes MCP servers. TulipMCPServer exposes the SDK's tools as MCP. |
| 🌐 Multi-modal | Agent(web_search=…, web_fetch=…, image_generator=…, speech_provider=…) auto-registers tools. |
| 📊 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.
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
Agent security
Security is the domain where Tulip's three control points pay off most visibly, so the SDK ships a first-class agent-security track.
Point a Target at an AI system — a remote endpoint, an in-process tulip.Agent, or an A2A
peer — and run the OWASP-ASI / MITRE-ATLAS suite. Every result is a grounded Evidence or an
explicit Abstention: a vulnerable target yields findings, a hardened one abstains across the
board.
from tulip.security import Target, red_team, assure, is_finding
target = Target.endpoint("https://support-bot.example/chat")
report = await red_team(target, suite="owasp-asi") # attack → grounded findings
for r in report:
print(r.title, r.taxonomy) if is_finding(r) else print("abstained:", r.reason)
posture = await assure(target) # assess → grounded guardrail coverage
The agent doing the work is itself governed by default — grounded, guarded, risk-gated (a dangerous-tool denylist on by default; allowlist opt-in), and recorded in a tamper-evident audit trail:
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
Evidence tags carry the standard catalogues — MITRE ATLAS (AML.Txxxx), OWASP Top 10
for LLM Applications (2025), and the OWASP Top 10 for Agentic Applications (2026) — so
findings drop into a SIEM or a NIST AI RMF report without a translation layer. Start with
notebook_37_gsar_typed_grounding.py.
Vendor security integrations
Core ships offline reference adapters for every security domain, so the SDK runs
standalone with no credentials. The maintained, vendor-specific integrations live in a
separate community package —
tulip-integrations (import
tulip_integrations) — which depends one-way on core (a core + community split).
pip install "tulip-integrations[edr-crowdstrike]" # + any per-vendor extra
| Domain | Vendors |
|---|---|
| SIEM | Splunk (Elastic-compatible SPL endpoint) |
| EDR | CrowdStrike Falcon |
| Identity | Okta · Auth0 |
| Threat intel | VirusTotal |
| Vuln / AI-SPM | Wiz |
| Compute | RunPod · Lambda (GPU fingerprint probe) |
Not to be confused with
tulip.integrations(this repo) — that's the built-in MCP client/server (MCPClient,TulipMCPServer). The communitytulip-integrationspackage is the vendor security adapters above.
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, 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 |
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.
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
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file tulip_agents-2.1.0.tar.gz.
File metadata
- Download URL: tulip_agents-2.1.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
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
16797adbf42e458d7420854e8ca7214ef14221625b961750b4a076e275084dd7
|
|
| MD5 |
cd362e99fb2d6c1413ee0a4d9beebc3b
|
|
| BLAKE2b-256 |
343a22d3ccda3d5925b78f51fb39f3718185d65116c888da25d008b246292c15
|
Provenance
The following attestation bundles were made for tulip_agents-2.1.0.tar.gz:
Publisher:
_release.yml on tuliplabs-ai/sdk-python
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
tulip_agents-2.1.0.tar.gz -
Subject digest:
16797adbf42e458d7420854e8ca7214ef14221625b961750b4a076e275084dd7 - Sigstore transparency entry: 2112313275
- Sigstore integration time:
-
Permalink:
tuliplabs-ai/sdk-python@ba5d4f06cabf88c2c45cd8113a8774b2d7fd690a -
Branch / Tag:
refs/tags/v2.1.0 - Owner: https://github.com/tuliplabs-ai
-
Access:
private
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
_release.yml@ba5d4f06cabf88c2c45cd8113a8774b2d7fd690a -
Trigger Event:
release
-
Statement type:
File details
Details for the file tulip_agents-2.1.0-py3-none-any.whl.
File metadata
- Download URL: tulip_agents-2.1.0-py3-none-any.whl
- Upload date:
- Size: 619.3 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.13
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
42b4ba635ba0d3127d0d22ddc99774a488358c1eaccc9daace5636f55d544036
|
|
| MD5 |
30b1bd819a05ddcf0853a00d34cb0180
|
|
| BLAKE2b-256 |
e9b3313d7b9775be2c2945acc57529dcb27139bbb0e314a282e3f6eefbaa61d7
|
Provenance
The following attestation bundles were made for tulip_agents-2.1.0-py3-none-any.whl:
Publisher:
_release.yml on tuliplabs-ai/sdk-python
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
tulip_agents-2.1.0-py3-none-any.whl -
Subject digest:
42b4ba635ba0d3127d0d22ddc99774a488358c1eaccc9daace5636f55d544036 - Sigstore transparency entry: 2112313294
- Sigstore integration time:
-
Permalink:
tuliplabs-ai/sdk-python@ba5d4f06cabf88c2c45cd8113a8774b2d7fd690a -
Branch / Tag:
refs/tags/v2.1.0 - Owner: https://github.com/tuliplabs-ai
-
Access:
private
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
_release.yml@ba5d4f06cabf88c2c45cd8113a8774b2d7fd690a -
Trigger Event:
release
-
Statement type: